Двойной указатель предупреждений о правильности в C
Указатель на неконстантные данные может быть неявно преобразован в указатель на константные данные того же типа:
int *x = NULL;
int const *y = x;
Добавление дополнительных квалификаторов const для сопоставления с дополнительным косвенным указанием должно логически работать так же:
int * *x = NULL;
int *const *y = x; /* okay */
int const *const *z = y; /* warning */
Компилируя это с GCC или Clang с -Wall
Однако флаг указывает на следующее предупреждение:
test.c:4:23: warning: initializing 'int const *const *' with an expression of type
'int *const *' discards qualifiers in nested pointer types
int const *const *z = y; /* warning */
^ ~
Почему добавление дополнительного const
квалификатор "отбрасывать квалификаторы во вложенных типах указателей"?
3 ответа
Причина по которой const
может быть добавлен только на один уровень глубже, это тонко, и это объясняется вопросом 11.10 в comp.lang.c FAQ.
Вкратце рассмотрим этот пример, тесно связанный с вашим:
const int i;
int *p;
int const **z = &p;
*z = &i;
/* Now p points to i */
C позволяет избежать этой проблемы, позволяя назначению отбрасывать квалификаторы только на первом указанном уровне (поэтому назначение z
здесь не допускается).
Ваш точный пример не страдает от этой проблемы, потому что const
второй уровень означает, что назначение *z
не будет разрешено в любом случае. C++ допускает это в этом конкретном случае, но более простые правила C не различают ваш случай и приведенный выше пример.
Запись FAQ, связанная с другим ответом, объясняет, почему следующий код не разрешен:
int **x = whatever;
const int **z = x;
Тем не менее, ваш код const int *const *z = x;
совсем другой, и он не страдает от того же недостатка, поднятого в FAQ.
На самом деле, концептуально нет ничего плохого в последнем коде. Это просто недостаток спецификации C, что это недопустимо, и это заставляет программистов на C включать в свой код некрасивые преобразования.
Для C было бы возможно использовать те же правила, что и для C++; однако комитет по стандартизации C не решил сделать это.
Причину, по которой автоматизм добавления квалификаторов работает только для 1-го уровня косвенности, можно прочитать из стандарта:
Стандарт утверждает в 6.5.16.1 для присваивания, что « оба операнда являются указателями на квалифицированные или неквалифицированные версии совместимых типов, а тип, на который указывает слева, имеет все квалификаторы типа, на который указывает справа »
Последняя часть предложения означает, что добавить квалификатор к указываемому типу не проблема.
И первая часть претендует на «совместимые» типы. И (я думаю,) 6.7.3 (11) описывает это для квалифицированных типов: « Чтобы два квалифицированных типа были совместимыми, оба должны иметь идентично квалифицированную версию совместимого типа ».
Читая это, ваши указанные типы не считаются совместимыми (даже если можно было бы назначить один другому).
Следовательно, я бы сказал, что предупреждение clang об отбрасывании квалификаторов немного вводит в заблуждение, но оно относится к неидентично квалифицированным указанным типам.