In this question, the example used is:
int * *x = NULL;
int *const *y = x; /* okay */
int const *const *z = y; /* warning */
Where int const *const *z = y; /* warning */
compiles with warning 'int const *const *' with an expression of type 'int *const *' discards qualifiers in nested pointer types
. The answer links to Question 11.10 in the comp.lang.c FAQ.
I am getting a similar warning when attempting to do:
char *x = strstr(...)
const char **z = &x;
But, after reading the answers & the FAQ, I still don't understand why the compiler discards the const
qualifier. From what I remember, *x = ...
does not affect &x
and &x
remains constant until x is reassigned (x = ...
).
In this post, the warning makes sense because there is non-const pointer to const, however I don't understand why there is a warning in this case.
CodePudding user response:
Say you have the following code:
char *p = strdup("bark");
const char **dp = &p;
Compiling and running with gcc in.c -o out.c -Wall -Wextra -pedantic -Wpedantic
:
warning: initialization of ‘const char **’ from incompatible pointer type ‘char **’ [-Wincompatible-pointer-types]
const char **dp = &p;
^
The warning message is clear: the two pointers are of incompatible types. To understand why this is problematic, try and modify the content of p
via dp
:
char *p = strdup("bark");
const char **dp = &p;
**dp = 'd';
Compile and run with the same command:
warning: initialization of ‘const char **’ from incompatible pointer type ‘char **’ [-Wincompatible-pointer-types]
const char **dp = &p;
^
error: assignment of read-only location ‘**dp’
**dp = 'd';
^
The const
in const char **dp
applies to the content at which *dp
is pointing to, namely p
(which is non-const
). That's why you see the incompatibility warning message.
Now, try and do:
char *p = strdup("bark");
const char **dp = &p;
*dp = strdup("dark");
The code compiles just fine (with the above warning). However, changing the above code to
char *p = strdup("bark");
char *const *dp = &p;
*dp = strdup("dark");
Will produce the following error:
error: assignment of read-only location ‘*dp’
*dp = strdup("dark");
^
Unlike in const char **dp
, the const
in char *const *dp
applies to the pointer at which dp
is pointing to, namely &p
. Therefore, changing it is not allowed.
Note that, in this same case, **dp = 'd';
will compile just fine (with the above warning).
You can go further and try:
char *p = strdup("bark");
const char *const *dp = &p;
*dp = strdup("dark"); // Error
**dp = 'p'; // Error
warning: initialization of ‘const char * const*’ from incompatible pointer type ‘char **’ [-Wincompatible-pointer-types]
const char *const *dp = &p;
^
error: assignment of read-only location ‘*dp’
*dp = strdup("dark");
^
error: assignment of read-only location ‘**dp’
**dp = 'x';
^
Maybe writing the syntax differently will make things clearer:
const char **dp == (const char)* *dp
char *const *dp == const (char*) *dp
const char *const *dp == const (const char)* *dp
CodePudding user response:
Consider the following example:
char* x = ...;
char const** z = &x;
char const* y = ...
y
can point to an array that's truely const (non-writable memory). y
is compatible to the declaration of z
, so you could do:
*z = y;
Now, though, x
– which z
points to – has been (legally from point of view of z
) assigned a const
(non-writable) array you might try to modify via the x
pointer (undefined behaviour)!
This is why the assignment of x
to z
is problematic, and this is why you get a warning issued, though admittedly the warning text could be a bit more precise. You consider it as in a way discarding the const
-ness of the target of z
by assigning a non-const pointer x
...