char a = 0;
char b[20] = {0};
char c[][20] = {{0}};
const char *aPtr;
const char *bPtr;
const char (*cPtr)[20];
char (*dPtr)[20];
void test(void)
{
aPtr = &a;
bPtr = b;
dPtr = &b;
dPtr = c;
cPtr = c; // warning here
}
cPtr = &c; Only this line of code generated a warning.
../source/bsw/user/PackParam_user.c:21:10: warning: assignment from incompatible pointer type
cPtr = c;
^
I would like to understand why this warning occurred for this specific line of code, while the other assignment statements do not trigger any warnings.
I use gcc v4.9
This compiler message is due to a defect in the C standard relating to
const
for arrays versus their elements.When assigning a pointer to another pointer, and neither points to
void
with or without qualifiers, the constraint in C 2018 6.5.16.1 1 is:In
cPtr = c;
,c
has typechar [1][20]
, and it is automatically converted to a pointer to its first element, so the resulting type ischar (*)[20]
. It is a pointer to typechar [20]
.cPtr
has typeconst char (*)[20]
. It is a pointer toconst char [20]
.C 2018 6.7.6.2 6 tells us “For two array types to be compatible, both shall have compatible element types…” But the element types,
const char
andchar
are not compatible, because 6.7.3 11 says “For two qualified types to be compatible, both shall have the identically qualified version of a compatible type…” Sochar [20]
andconst char [20]
are not compatible types.Now you might say that
const char [20]
has all the qualifiers ofchar [20]
, and the assignment constraint allows assignment of pointers if they point to compatible types except the operand’s pointed-to type has more qualifiers. However, theconst
modifies the element type,char
, not the pointed-to type, array of 20char
. The constraint would allow assigning “pointer to array of 20char
” to “pointer toconst
array of 20char
.” But those are not the types involved.They should be the types involved. This is a defect in the C standard. An array of 20
const char
should be the same as aconst
array of 20char
. If the array elements areconst
, the array itself is actuallyconst
too—any attempt to modify the array is an attempt to modify its elements and vice-versa. The array is its elements, so the identifiers of the array and the elements ought to be one single thing. But writing rules for this is complicated, and it was not done in the C standard up to 2018.The C standard has some attempt to deal with qualifiers on arrays. You could attempt to make
cPtr
a pointer to aconst
array of 20char
by using atypedef
:typedef char CharArray[20]; const CharArray *cPtr;
. However, C 2018 6.7.3 10 magics this qualifier away, moving it from the array to the elements: “If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type…” In retrospect, that was insufficient, as it does not solve the problems with array qualifiers.Compiler writers are aware this is a defect in the standard, and they try to work around it, which is why GCC was modified not to give this warning unless specifically requested with
-pedantic
.