17

I have a function taking a static two-dimensional array and treating the elements of the elements of the array as being constant:

void test_function(const char arr[3][3]);

I am trying to call such a function as follows:

char my_var[3][3] = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} };
test_function(my_var);

When compiling with gcc (without any flag), I get the following warning:

test.c:9:8: warning: passing argument 1 of 'test_function' from incompatible pointer type
   test_function(my_var);
                 ^
test.c:4:6: note: expected 'const char (*)[3]' but argument is of type 'char (*)[3]'
 void test_function(const char arr[3][3]);

If I remove the const from test_function's prototype, the warning goes away. But it is not really what I want.

When compiling with clang with both -pedantic-errors and -Wall I don't get any warning about pointer incompatibility.

I just would like to understand why gcc outputs such a warning in this case. Why would my pointers/arrays be incompatible?

edmz
  • 8,220
  • 2
  • 26
  • 45
Julien Thierry
  • 651
  • 4
  • 11
  • I want to say this is a GCC bug - the fact that Clang produces no diagnostic at all makes me quite suspicious. By the way, you should note that it is actually a warning, not an error (you appear to have been compiling with `-Werror`). – nneonneo Feb 24 '15 at 17:04

2 Answers2

12

GCC is right to the letter of the standard and Clang is wrong.

6.3.2.3/2:

For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type;

Looks very promising. But hold on.

6.2.5/26:

A derived type is not qualified by the qualifiers (if any) of the type from which it is derived

This provision of the standard as applied specifically to arrays is not necessary, and could be easily reversed. That is, const char[3] could be easily made a const-qualified version of char[3]. But it is not. They are just different, incompatible types. In fact there are no const-qualified array types in C at all, so you can't have a const-qualified version of char[3]. That's the standard we have and must live with.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 1
    Then why does gcc not issue a warning in the case of a function taking `const char[3]` as parameter and passing a variable of type `char[3]`? – Julien Thierry Feb 24 '15 at 18:14
  • 5
    Because `const char[3]` as a function parameter is a lie. It is silently treated as a `const char*`. The actual argument is decayed to a `char*`. Then the whole business is covered by 6.3.2.3/2 which I quoted. – n. m. could be an AI Feb 24 '15 at 19:14
6

From the C-FAQ [Question 11.10]

In C, if you must assign or pass pointers which have qualifier mismatches at other than the first level of indirection, you must use explicit casts (e.g. (const char **) in this case), although as always, the need for such a cast may indicate a deeper problem which the cast doesn't really fix.

In your case:

test_function((const char (*)[3])my_var);
David Ranieri
  • 39,972
  • 7
  • 52
  • 94