4

My understanding is that

char (*)[20]

is a pointer to an array of 20 non-const chars, while

const char (*)[20]

is a pointer to an array of 20 const chars.

In the following code, I am passing a pointer to an array of non-const chars to a function which expects a pointer to an array of const chars. Inside the function, the compiler properly catches write accesses to the array, as expected:

#include <stdlib.h>

void f(const char (*param)[20]) {
   /* correctly catched by the compiler: assignment of read-only location '(*param)[2]' */
   /* (*param)[2] = 'A'; */
}

int main() {
   char (*data)[20] = calloc(20, 1);

   f(data);

   return 0;
}

However, I am getting the following warning at the function call:

$ gcc -Wall -pedantic -o so so.c
so.c: In function 'main':
so.c:15:4: warning: passing argument 1 of 'f' from incompatible pointer type [enabled by default]
    f(data);
    ^
so.c:3:6: note: expected 'const char (*)[20]' but argument is of type 'char (*)[20]'
 void f(const char (*param)[20]) {
      ^

Why is that? Should it not always be possible to pass a pointer to non-const data to a function which expects a pointer to const data of the same type?

I know that there are other solutions to this, but I am particularly interested in understanding why the compiler gives this warning in this specific situation.

Community
  • 1
  • 1
Andreas Fester
  • 36,091
  • 7
  • 95
  • 123
  • 1
    I'm not sure if this makes any difference to the resoning, but `const char (*)[20]` is a pointer to an array of 20 `const char`. An array is its elements, so it is hard to imagine what a `const` array with non-const elements would be. – juanchopanza Sep 25 '14 at 12:11
  • `clang a.c -Wall -pedantic` gives no warning at all. – starrify Sep 25 '14 at 12:17
  • @juanchopanza Maybe my phrasing was not choosen too well :-) - essentially the question is why I get this warning when passing a pointer to writable memory to a function which expects read-only memory. IMHO it should always be possible in that direction (of course **not** the other way round...) – Andreas Fester Sep 25 '14 at 12:21
  • This seems ok, syntactically: http://ideone.com/kOukUX – Wolf Sep 25 '14 at 12:24
  • For what is worth, the same code with G++ does not emit the warning. – rodrigo Sep 25 '14 at 12:30
  • @rodrigo Which version of `g++` are you using? I've tried `g++ 4.9.1` and it gives an error at line 9 saying invalid conversion from ‘void*’ to ‘char (*)[20]’ – starrify Sep 25 '14 at 12:38
  • @starrify: Well, I patched that part that is obviously non-C++-ish. BTW, it is G++ 4.8.2. – rodrigo Sep 25 '14 at 12:43
  • 3
    Please, see [this GCC FAQ](https://gcc.gnu.org/wiki/FAQ#constmismatch). TLDR: "This is how C works". – rodrigo Sep 25 '14 at 13:05
  • 1
    @rodrigo Excellent - the linked [C FAQ](http://archive.today/mGvX7) boils it down to the fact that you **can** assign `T*` to `const T*`, but **not** `T**` to `const T**` (at any pointer level > 1). It also says "The reason ... is somewhat obscure" - well, yes ... Anyway, if you like, post an answer and I will be happy to accept it! – Andreas Fester Sep 25 '14 at 13:14
  • @Andreas: Oh my! The question has been closed as duplicated while I was writing!! Well... that's SO. – rodrigo Sep 25 '14 at 13:20
  • @rodrigo Yes, just saw it, sorry for that - I did not find the duplicate answer before, maybe I was too focused on "passing as parameter" ... – Andreas Fester Sep 25 '14 at 13:23

0 Answers0