1
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

yyd
  • 33
  • 5
  • Can't reproduce the warning (MS VC), but please post the full *actual* code (there's an error) copy/pasted exactly as it is. – Weather Vane Aug 08 '23 at 11:13
  • I couldn't get a warning with gcc on Linux until I added `-pedantic`. Then I got `warning: pointers to arrays with different qualifiers are incompatible in ISO C` – pmacfarlane Aug 08 '23 at 11:26
  • @WeatherVane: Once the missing `;` after `dPtr = &b` is added, it reproduces on Godbolt with GCC 4.1.0 to 4.9.4 and with later versions when `-std=c18 -pedantic` is used. This is related to a defect in the C standard regarding how `const` applies to arrays. The C standard does not actually specify that an array of `const char` is also `const`. Looks related to [this](https://stackoverflow.com/questions/54507856/is-gcc-warning-on-const-qualifier-correct). – Eric Postpischil Aug 08 '23 at 11:36
  • @Eric Postpischil I see, thanks. MS VC is still silent with `/Wall`. – Weather Vane Aug 08 '23 at 11:42
  • @EricPostpischil, use gcc 8.1 with -pedantic, the warning is 'different qualifiers are incopatible', but gcc4.9 report warning 'incopatible pointer type'.And 'dPtr' without const is no warning. – yyd Aug 08 '23 at 11:48
  • @molly I would suggest upgrading your compiler :) 9 years is a very long time in computers – 0___________ Aug 08 '23 at 11:50
  • https://godbolt.org/z/aWdKPqvzP – 0___________ Aug 08 '23 at 11:53
  • With gcc-12.2.0 and compiling under -std=c17 I get `warning: invalid use of pointers to arrays with different qualifiers in ISO C before C2X [-Wpedantic]`. The C23 Standard has changed the wording around the semantics of `const` qualifiers (C23 §6.7.3 10), and compiling with `-std=c2x` makes the warning go away. – ad absurdum Aug 08 '23 at 14:08

1 Answers1

3

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.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • The issue has been discussed in [N1923](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1923.htm). C23 has changed the semantics of `const`: _"If the specification of an array type includes any type qualifiers, both the array and the element type are so-qualified"_ (C23 §6.7.3 10). When I compile OP code with `gcc -std=c2x -Wall -Wextra -Wpedantic` the warning goes away. – ad absurdum Aug 08 '23 at 14:55
  • @adabsurdum: I am not sure they have really fixed the problem. That rule would make `cPtr` have type “pointer to `const` array of 20 `const char`.” In draft N3054, dated September 3, 2022, 6.7.6.2 6 still says “For two array types to be compatible, both shall have compatible element types,” and `const char` is not compatible with `char`. The constraint for assignment also does not appear to be adjusted to allow for this. – Eric Postpischil Aug 08 '23 at 15:00
  • @adabsurdum: Also not fixed in N3096, April 2023. I think they need to change the assignment constraints to acknowledge that the elements of a pointed-to array may have additional qualifiers (matching the array). – Eric Postpischil Aug 08 '23 at 15:05
  • The discussion in N1923 suggests that the problem was that §6.3.2.3 (_"a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type"_) did not apply to pointers to arrays before the wording change in §6.7.3 10 because a pointer to an array was not a pointer to a qualified type. My reading of this is that the inability to apply the conversion rule to pointers to arrays made it impossible to convert `char (*)[]` to `const char (*)[]`. Doesn't this fix the compatibility issue? – ad absurdum Aug 08 '23 at 15:23
  • 1
    @adabsurdum: No, because the constraints for assignment are not predicated on whether or not the right operand can be converted to the type of the left operand. They say the operands must be pointers to qualified or unqualified versions of compatible types and the left operand has all the qualifiers of the type pointer to by the right operand. `c` (after array-to-pointer conversion) and `cPtr` are not pointers to qualified or unqualified versions of compatible types. Looks like the committee overlooked the need to change this. – Eric Postpischil Aug 08 '23 at 15:29