TL; DR:
- В (1) оба квалификатора 1-го и 2-го
volatile
относятся к int
, таким образом, являясь "дубликатами" в терминах gcc? (Я смотрю на C99 6.7.3.4 здесь.)
Да, они оба квалифицируют int
, и они дубликаты.
- В (2) один из энергозависимых квалификаторов ссылается на тип массива, а
not
на int или на сам указатель, так что C99 6.7.3.8 содержит:
C99 6.7.3.8 не удерживается здесь. Квалификатор уже применяется к типу элемента. Можно применить квалификатор к массиву с typedef, но это также определяет тип элемента (см. Ниже)
с. Если ответ на b отрицательный, как я могу объявить тип изменяемого массива, который описан в C99 6.7.3.8?
Например, typedef
.
Стандарт C явно разрешает квалификаторы встречаться более одного раза. C11 n1570 6.7.3p5 :
Если один и тот же классификатор появляется более одного раза в одном и том же списке спецификаторов-спецификаторов, либо напрямую, либо через одну или несколько типов определений, поведение такое же, как если бы оно появилось только один раз.
т.е. что -Wduplicate-decl-specifier
не является ошибкой как таковой, но такой кодовый дословный код является подозрительным - если это был volatile int *volatile
, который был опечатан как volatile int volatile *
, вызывая неквалификацию указателя ...
Квалификаторы применяются к типу левого левого классификатора, за исключением случаев, когда сам классификатор является крайним левым, и в этом случае он выглядит так, как если бы он был правым от базового типа, т.е.
volatile int *
и
int volatile *
означает то же самое. Поэтому в volatile int volatile
вы можете удалить один из них. Таким образом, то, что вам нужно, это
volatile int *volatile vipa[10];
То есть випа is an array of 10
летучий -qualified pointers to
летучий
int`s.
Что означает C99 6.7.3p8 / C11 6.7.3p9, так это то, что массив сам по себе не может быть энергозависимым - его адрес постоянен, только его элементы могут быть определены. следовательно, если тип массива определен, он применяется только к его элементам. Это даже так, если typedef квалифицирован:
typedef int intarray[5];
const intarray myarray;
объявит myarray
как бы
const int myarray[5];
тогда как если бы вы использовали typedef для указателя:
typedef int *intptr;
const intptr myptr;
этот классификатор не будет влиять на указательный тип, но будет эквивалентен
int *const myptr;
В то время как volatile int
и int volatile
строго разрешены, стандарт C предпочитает первый. C11 n1570 6.7.6.1p3 :
ПРИМЕР Следующая пара объявлений демонстрирует разницу между '' указателем переменной на постоянное значение '' и '' указателем константы на значение переменной ''.
const int *ptr_to_constant;
int *const constant_ptr;
Содержимое любого объекта, на который указывает ptr_to_constant
, не должно изменяться через этот указатель, но само ptr_to_constant
может быть изменено, чтобы указывать на другой объект. Аналогично, содержимое int
, на которое указывает constant_ptr
, может быть изменено, но сам constant_ptr
всегда должен указывать на одно и то же местоположение.
Кроме того, можно добавить спецификатор типа для массива в скобках, но только в параметрах функции, поэтому вы можете написать
void foo(int array[volatile])
, что означает почти то же самое , и параметр распадается на квалифицированный указатель
void foo(int *volatile array)
но вы можете использовать спецификатор static
только с прежним стилем.