Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC Incompatible pointer type using a typedef

Tags:

c

pointers

gcc

I have some code that compiled fine under GCC 4.8.4. I've recently upgraded my system and now have GCC 5.2.1, and I'm getting a warning about incompatible pointer types. I've extracted the problem to a small example that reproduces the error:

typedef const double ConstSpiceDouble;
void foo(const double (*)[3]); 

int main(int argc, char **argv) {
  double a[3][3] = {{1,2,3},{1,2,3},{1,2,3}};

  foo((ConstSpiceDouble (*)[3])a);

  return 0;
}

In the real code, the typedef, the function definition, and the type cast are in a library outside of my control otherwise I would just fix the cast and the function to match. Here's the message I get from the compiler:

$ gcc -Werror -c test.c
test.c: In function ‘main’:
test.c:9:7: error: passing argument 1 of ‘foo’ from incompatible pointer type [-Werror=incompatible-pointer-types]
   foo((ConstSpiceDouble (*)[3])a);
       ^
test.c:4:6: note: expected ‘const double (*)[3]’ but argument is of type ‘const ConstSpiceDouble (*)[3] {aka const double (*)[3]}’
 void foo(const double (*)[3]);
      ^
cc1: all warnings being treated as errors

The note from gcc is especially troubling since it seems to admit that the two types are identical, yet it complains anyway.

like image 704
Gravatite Avatar asked Oct 27 '15 19:10

Gravatite


2 Answers

The consensus here and elsewhere seems to be that GCC is doing something unexpected with the const and the typedef. I don't know that unexpected necessarily equates to a bug, but that's for the GCC devs to determine.

I have solved my compilation problem by defining a macro for the function call that fixes the non-matching typecast that's inside the library. I generally dislike tinkering with library internals, but the macro allows me to not touch the actual library header and define it in my own code where it can be commented for the future, and test coverage of that code should be a reasonable early warning signal if the underlying library changes in such a way that the macro breaks something down the road.

This isn't so much "solved" as "worked around", but any further insight will likely have to come from the GCC devs.

like image 106
Gravatite Avatar answered Oct 29 '22 22:10

Gravatite


If you type cast 'a' to be ConstSpiceDouble, GCC is doing something unexpected with the const and the typedef, by which eventually the type becomes 'const const double'. This you can see in the error message "const ConstSpiceDouble", which equates to 'const const double', this does not work.

Solution is to either say 'a' is const double or to say 'a' is ConstSpiceDouble before you parameter 'a' to the foo function

typedef const double ConstSpiceDouble;
void foo(const double (*)[3]); 

int main(int argc, char **argv) {

  const double a[3][3] = {{1,2,3},{1,2,3},{1,2,3}};
  // or ConstSpiceDouble a[3][3] = {{1,2,3},{1,2,3},{1,2,3}};

  foo(a);

  return 0;
}

The 'const' pre-pending seems to be a new feature in the latest versions of gcc, but of that, I am not sure :(

like image 34
hewi Avatar answered Oct 29 '22 20:10

hewi