Search code examples
cpointersgcc-warningconst-pointer

Warning about assignment of pointer to const pointer


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


Solution

  • 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:

    … both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right…

    In cPtr = c;, c has type char [1][20], and it is automatically converted to a pointer to its first element, so the resulting type is char (*)[20]. It is a pointer to type char [20].

    cPtr has type const char (*)[20]. It is a pointer to const 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 and char 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…” So char [20] and const char [20] are not compatible types.

    Now you might say that const char [20] has all the qualifiers of char [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, the const modifies the element type, char, not the pointed-to type, array of 20 char. The constraint would allow assigning “pointer to array of 20 char” to “pointer to const array of 20 char.” 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 a const array of 20 char. If the array elements are const, the array itself is actually const 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 a const array of 20 char by using a typedef: 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.