I am able to pass a const
pointer as argument of a function that takes non-const
pointer.
Furthermore, inside the function body, I was allowed to modify its value as well with only a warning:
(passing argument 1 of 'modifyValue' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
)
from the compiler but no error.
#include <stdio.h>
void modifyValue(int *ptr) {
*ptr = 10; // This modifies the value pointed to by ptr
}
int main() {
const int value = 5;
const int *constPtr = &value;
// This doesn't cause a compilation error
modifyValue(constPtr);
printf("%d",*constPtr);
return 0;
}
demo
Is this behavior consistent with C spec? I would have assumed one could not pass const
value as non-const
argument as it strips away the const
-ness. What is the point of the const
qualifier if you can pass it through a function and change the value all the same?
I am able to pass a const
pointer as argument of a function that takes non-const
pointer.
Furthermore, inside the function body, I was allowed to modify its value as well with only a warning:
(passing argument 1 of 'modifyValue' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
)
from the compiler but no error.
#include <stdio.h>
void modifyValue(int *ptr) {
*ptr = 10; // This modifies the value pointed to by ptr
}
int main() {
const int value = 5;
const int *constPtr = &value;
// This doesn't cause a compilation error
modifyValue(constPtr);
printf("%d",*constPtr);
return 0;
}
demo
Is this behavior consistent with C spec? I would have assumed one could not pass const
value as non-const
argument as it strips away the const
-ness. What is the point of the const
qualifier if you can pass it through a function and change the value all the same?
2 Answers
Reset to default 7Because C gives you enough rope to shoot yourself in the foot ^ACM.
I think the warning errors are enough:
~ » clang main.c
main.c:12:17: warning: passing 'const int *' to parameter of type 'int *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
12 | modifyValue(constPtr);
| ^~~~~~~~
main.c:3:23: note: passing argument to parameter 'ptr' here
3 | void modifyValue(int *ptr) {
| ^
1 warning generated.
» gcc main.c
main.c: In function ‘main’:
main.c:12:17: warning: passing argument 1 of ‘modifyValue’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
12 | modifyValue(constPtr);
| ^~~~~~~~
main.c:3:23: note: expected ‘int *’ but argument is of type ‘const int *’
3 | void modifyValue(int *ptr) {
| ~~~~~^~~
Try running with -Werror
~ » clang -Werror main.c
main.c:12:17: error: passing 'const int *' to parameter of type 'int *' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
12 | modifyValue(constPtr);
| ^~~~~~~~
main.c:3:23: note: passing argument to parameter 'ptr' here
3 | void modifyValue(int *ptr) {
| ^
1 error generated.
~ » gcc -Werror main.c
main.c: In function ‘main’:
main.c:12:17: error: passing argument 1 of ‘modifyValue’ discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
12 | modifyValue(constPtr);
| ^~~~~~~~
main.c:3:23: note: expected ‘int *’ but argument is of type ‘const int *’
3 | void modifyValue(int *ptr) {
| ~~~~~^~~
cc1: all warnings being treated as errors
Is this behavior consistent with C spec?
Yes - the compiler gave you some sort of message, which is all that is required. What must a C compiler do when it finds an error?
There's a common misunderstanding among beginners that warnings mean "here's a little cosmetic trifle you can fix some rainy day". In this case it meant "here's a severe bug - your program isn't even valid C". But for whatever the reason the compiler chose to generate an executable anyway - what that executable does is anyone's guess since it is a "not C program".
That's why I recommend beginners to enable all warnings and also set -Werror -pedantic-errors
in case of gcc-like compilers.
Specifically, the program contains a constraint violation against the rules of assignment:
C23 6.5.3.3 Function calls
The arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters
So basically the call modifyValue(constPtr);
is the same as int* ptr = constPtr;
. We must therefore go and check the rules of assignment, C23 6.5.17.2, emphasis mine:
Constraints
the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;
"qualifier" meaning type qualifier such as const
. The left operand in this case is the function parameter, int *ptr
, and the right operand is the function argument, const int *
. The left operand does not have the const
qualifier of the right operand, so this is a "constraint violation" - text found underneath the headline "constraints" in the C standard was violated, meaning that the code is invalid C and the compiler must give some sort of diagnostic message.
-Werror=discarded-qualifiers
– robthebloke Commented Mar 17 at 4:52-Werror
as a compiler option by default along with-Wall -Wextra -pedantic -Wshadow
. While you are learning, having full warnings enabled and treating all warnings as errors ensure you fix the warnings (and as a side-effect learn quite a bit of C from your compiler). It's quite a good teacher. – David C. Rankin Commented Mar 17 at 4:59char* str = "hello world"; ... strcpy(&msg[6], "dino");
. Then later in the Cretaceous period, a meteor in the form of ISO C90 hit. But some compilers like gcc still thought it was still more important to preserve code written by the long-since extinct brontosaurus than to block "const to not const" conversions. Which is also the reason that the C90 dinosaurs from the Cretaceous period insisted that string literals in C must bechar[]
and notconst char[]
. – Lundin Commented Mar 17 at 10:13