Несовместимые типы указателей и константы
У меня есть функция, принимающая статический двумерный массив и рассматривающий элементы элементов массива как постоянные:
void test_function(const char arr[3][3]);
Я пытаюсь вызвать такую функцию следующим образом:
char my_var[3][3] = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} };
test_function(my_var);
При компиляции с gcc (без какого-либо флага) я получаю следующее предупреждение:
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]);
Если я удалю прототип const
из test_function
, предупреждение исчезнет. Но это не совсем то, что я хочу.
При компиляции с clang как с -pedantic-errors
, так и -Wall
я не получаю предупреждения о несовместимости указателя.
Я просто хотел бы понять, почему gcc выводит такое предупреждение в этом случае.
Почему мои указатели/массивы несовместимы?
Ответы
Ответ 1
GCC имеет право на букву стандарта, а Clang ошибочен.
6.3.2.3/2:
Для любого определителя q указатель на не-q-квалифицированный тип может быть преобразован в указатель на q-квалифицированную версию типа;
Выглядит очень многообещающе. Но держитесь.
6.2.5/26:
Производный тип не определяется квалификаторами (если они есть) того типа, из которого он получен
Это положение стандарта, применяемого специально для массивов, не является необходимым и может быть легко отменено. То есть const char[3]
может быть легко сконструирована с использованием const-версии версии char[3]
. Но это не так. Это просто разные, несовместимые типы. На самом деле в C нет никаких типов конструкций с независимым от const-типа, поэтому вы не можете иметь версию char[3]
с поддержкой const. Это стандарт, который мы имеем и должен жить.
Ответ 2
Из C-FAQ [Вопрос 11.10]
В C, если вы должны назначить или передать указатели, которые имеют квалификатор несоответствие, отличное от первого уровня косвенности, вы должны использовать явные приведения (например, (const char **) в этом случае), хотя как всегда, необходимость в таком акте может указывать на более глубокую проблему, которая литье действительно не исправляется.
В вашем случае:
test_function((const char (*)[3])my_var);