7

When I compile the program below with GCC 4.9.2 I get the following warning: passing argument 1 of ‘P’ from incompatible pointer type. However, I don't see anything wrong with the program. Any clues?

typedef int Row[10];

void P(const Row A[])
{
}


int main(void)
{
    Row A[10];

    P(A);
    return 0;
}

Here is the complete output from GCC to stderr:

test.c: In function ‘main’:
test.c:12:4: warning: passing argument 1 of ‘P’ from incompatible pointer type
  P(A);
    ^
test.c:3:6: note: expected ‘const int (*)[10]’ but argument is of type ‘int (*)[10]’
 void P(const Row A[])
      ^

Edit: The program compiles cleanly with Clang 3.5.0 and the options -pedantic -std=c89 -Wall.

August Karlstrom
  • 10,773
  • 7
  • 38
  • 60
  • 2
    what do you think about `const` qualifier? – Sourav Ghosh Dec 16 '16 at 09:12
  • @SouravGhosh I think it promises the caller that the parameter *A* will not change. – August Karlstrom Dec 16 '16 at 09:13
  • Yes, so, the function expects.......? – Sourav Ghosh Dec 16 '16 at 09:14
  • GCC is usually quite verbose with its messages. There are no informational notes it printed that could give you any hints about the problem? Like what the function expects and what the function actually got? – Some programmer dude Dec 16 '16 at 09:17
  • @Someprogrammerdude Added the warnings from GCC – August Karlstrom Dec 16 '16 at 09:20
  • 1
    @SouravGhosh The function expects a parameter of type `int (*)[10]`, constant or not. Do you have a different opinion? – August Karlstrom Dec 16 '16 at 09:22
  • Do you want something like http://ideone.com/g0RxuW ? – mch Dec 16 '16 at 09:36
  • I re-opened this since I believe this question is better/cleaner than the [linked-duplicate](http://stackoverflow.com/questions/33726130/im-getting-incompatible-pointer-type-and-i-dont-understand-why) and I had written a more detailed answer at the point this was closed. Also the linked dupe has a very long and confusing answer not related to qualifiers of array pointers. Perhaps the linked duplicate should be closed as a dupe to this one instead (there is no doubt they are dupes). I will however refrain from further moderation of this post, as I'm now partial with a posted answer. – Lundin Dec 16 '16 at 09:45
  • Curiously, gcc 6.2 issues no warnings for this code, which I guess is because of [this](https://gcc.gnu.org/onlinedocs/gcc/Pointers-to-Arrays.html) - which might be a new feature since gcc 4.9.2 that the OP uses. – nos Dec 16 '16 at 09:54
  • @nos You have to compile as standard C. – Lundin Dec 16 '16 at 10:04
  • @Lundin I'm just remarking that there is a difference, gcc 4.9.2 issues the warning both with and without e.g. -Wall -Wextra -std=c99 , gcc 6.2 issues no such warning (unless the -pedantic flag is also added apparently) – nos Dec 16 '16 at 10:05
  • @nos Ok then there is a compiler bug. If you use `-std=c99` you should have gotten a diagnostic. The link you posted explicitly states this too. – Lundin Dec 16 '16 at 10:06
  • (Obviously the -std=gnu11 people want to add this non-standard extension as a way to show how the language could be improved. So it is a good extension, but sadly not standard compliant (yet).) – Lundin Dec 16 '16 at 10:09

1 Answers1

8

Get rid of the typedef and it should become a little bit clearer:

void P (const int A [][10])
{
}

int main(void)
{
    int A[10][10];

    P(A);
    return 0;
}

The problem is that the array in the function parameter "decays" into a pointer of type const int(*) [10], which is a pointer to an array where the items are const.

This pointer type is not compatible with what you pass from main, because that array decays into an array pointer of type int(*)[10].

There is a rule of "pointer-to-type may be converted to qualified-pointer-to-type". Meaning for example int* may be converted to const int* but not the other way around. But that rule does not apply here.

Because the qualified version of "pointer-to-array" is "const-pointer-to-array", and not "pointer-to-const-array", which is what you have here.

Unfortunately this is a weakness in the C language: you cannot have const correctness while using array pointers. The only solution is a very ugly one:

P( (const int(*)[10]) A);

It might be better to skip const correctness completely for cases like this, in favour of readability.


Edit: In C11 you can do like this, which is more type safe but it still relies on the caller performing a cast:

#define const_array_cast(arr, n) _Generic(arr, int(*)[n] : (const int(*)[n])arr )

void P (const int A [][10])
{
}


int main(void)
{
    int A[10][10];

    P(const_array_cast(A,10));
    return 0;
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • It is not required to pass a `const` to a function that has a `const` parameter. The `const` in the function just says that the parameter will not be modified in the function. See for e.g. `strcmp` functions. – Rishikesh Raje Dec 16 '16 at 09:54
  • The program compiles cleanly with Clang 3.5.0 with the options `-pedantic -std=c89 -Wall`. Does this mean that there is a bug in Clang? – August Karlstrom Dec 16 '16 at 09:54
  • 2
    @RishikeshRaje Please read my answer again, I have explicitly addressed what you are saying, it does not apply here. – Lundin Dec 16 '16 at 09:55
  • [Related question](http://stackoverflow.com/questions/36199473/const-correctness-for-array-pointers). – Lundin Dec 16 '16 at 09:56
  • @AugustKarlstrom That sounds like a compiler bug indeed. – Lundin Dec 16 '16 at 10:05