Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC issues warning of incompatible pointer type

Tags:

c

gcc

gcc-warning

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.

like image 836
August Karlstrom Avatar asked Dec 16 '16 09:12

August Karlstrom


1 Answers

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;
}
like image 94
Lundin Avatar answered Nov 05 '22 23:11

Lundin