Интересно, что я мог бы скомпилировать следующий код с версиями CLang 3.4.1 и 6.0.0 без предупреждений:
#include <stdio.h>
void print_foo(const int (* const foo)[3]) {
printf("%d - size: %lu\n", (*foo)[1], sizeof(*foo));
}
int main() {
int foo[3] = {1,2,3};
print_foo(&foo);
return 0;
}
В моей 32-битной системе вывод 2 - 12
, что доказывает, что sizeof(*foo)
имеет ожидаемое значение.
Но я бы сказал, что gcc здесь верный, и что Clang допускает его как расширение.
Стандарт (черновик n1570 для C11) гласит 6.2.7 Совместимый тип и составной тип §1:
Два типа имеют совместимый тип, если их типы совпадают.Дополнительные правила определения совместимости двух типов описаны в 6.7.2 для спецификаторов типов, в 6.7.3 для классификаторов типов и в 6.7.6 для деклараторов и в 6.7.3 классификаторах типов § 10
Длядва квалифицированных типа должны быть совместимы, оба должны иметь идентично квалифицированную версию совместимого типа
Таким образом, типы должны иметь одинаковую константность для совместимости.
Но передача параметров ввызов функции имеет ту же семантику, что и присваивание, и 6.5.16.1 простое присваивание говорит в своих ограничениях:
Должно выполняться одно из следующего:...левый операнд имеет атомарный, квалифицированный или неквалифицированный тип указателя, и (учитывая тип, который левый операнд будет иметь после преобразования в lvalue) оба операнда являются указателями на квалифицированные или неквалифицированные версии совместимых типов, а тип, на который указывает левый, имеет всеквалификаторы типа, указанного справа
Итак, разрешено присваивать int (*)[3]
int (const *)[3]
, даже если они несовместимы.
Ноint [3]
и const int[3]
- это разные типы, поэтому вы не можете присвоить int (*)[3]
для const int (*)[3]
или const int (const *)[3]
.
То, что вы хотите, имеет смысл, но я не могу представить себе подходящий способобъявить это.