GCC Несовместимый тип указателя с использованием typedef

У меня есть код, который скомпилирован под GCC 4.8.4. Недавно я обновил свою систему и теперь имею GCC 5.2.1, и я получаю предупреждение о несовместимых типах указателей. Я извлек проблему на небольшой пример, который воспроизводит ошибку:

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; } 

В реальном коде typedef, определение функции и тип cast находятся в библиотеке за пределами моего элемента управления, иначе я просто исправлю листинг и функцию для соответствия. Вот сообщение, которое я получаю от компилятора:

 $ 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 

Заметка gcc особенно беспокоит, так как кажется, что два типа идентичны, но все равно жалуются.

Консенсус здесь и в других местах, похоже, заключается в том, что GCC делает что-то неожиданное с константой и typedef. Я не знаю, что неожиданность обязательно приравнивается к ошибке, но это нужно для разработчиков GCC.

Я решил проблему с компиляцией, указав макрос для вызова функции, который фиксирует несовпадающий тип-метод, который находится внутри библиотеки. Мне вообще не нравится возиться с внутренними библиотеками, но макрос позволяет мне не касаться фактического заголовка библиотеки и определять его в моем собственном коде, где его можно прокомментировать в будущем, и проверить охват этого кода должен быть разумным сигналом раннего предупреждения, если основная библиотека изменяется таким образом, что макрос нарушает что-то в будущем.

Это не так «решено», как «работало», но любое дальнейшее понимание, скорее всего, должно исходить от разработчиков GCC.

Если вы наберете «a», чтобы быть ConstSpiceDouble, GCC делает что-то неожиданное с константой и typedef, благодаря которой тип становится «const const double». Это вы можете увидеть в сообщении об ошибке «const ConstSpiceDouble», которое приравнивается к «const const double», это не работает.

Решение состоит в том, чтобы сказать «a» – это const double или сказать «a» – это ConstSpiceDouble, прежде чем вы установите параметр «a» в функцию foo

 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; } 

Предполагаемая предварительная работа «const» кажется новой функцией в последних версиях gcc, но я не уверен 🙁