Рассмотреть возможность
volatile int volatile * volatile vip; // (1)
а также
volatile int volatile * volatile vipa[10]; // (2)
Обе строки кода вызывают -Wduplicate-decl-specifier (см. версия 236142
и примечания к выпуску gcc7). Я хотел бы знать, могу ли я удалить некоторые спецификаторы volatile из данного кода без изменения семантики кода, а также понять причины этого.
Таким образом, следующие вопросы:
а. В (1) относятся ли 1-й и 2-й квалификаторы volatile к int, таким образом, являясь «дублирующими» в терминах gcc? (Я смотрю здесь C99 6.7.3.4.)
б. В (2) относится ли один из квалификаторов volatile к типу массива, а не к int или самому указателю, так что C99 6.7.3.8 выполняется:
If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type.
или спецификаторы volatile в (2) влияют только на int и тип pointer, а не на тип массива?
с. Если ответ на б отрицательный, как мне объявить тип массива volatile, описанный в C99 6.7.3.8? Это синтаксис, описанный в https://en.cppreference.com/w/c/language/array (цитата следует)?
qualifiers - any combination of const, restrict, or volatile qualifiers, only allowed in function parameter lists; this qualifies the pointer type to which this array parameter is transformed
Давайте рассмотрим этот вопрос о C99. Если есть какие-либо различия в C11 в этом отношении, пожалуйста, сделайте пометку.





TL;DR:
- In (1), do the 1st and 2nd
volatilequalifiers both refer toint, thus being "duplicate" in gcc terms? (I'm looking at C99 6.7.3.4 here.)
да, они оба соответствуют int и являются дубликатами в.
- In (2), does one of the volatile qualifiers refer to the type of the array, and
notthe int or the pointer itself, so that C99 6.7.3.8 holds:
C99 6.7.3.8 содержит ли здесь нет. Квалификатор уже применяется к типу элемента. К массиву с typedef можно применить квалификатор, но это также квалифицирует тип элемента (см. ниже).
c. If the answer to b is negative, how do I declare a volatile array type that is described in C99 6.7.3.8?
Например, с typedef.
Стандарт C явно разрешает использование квалификаторов более одного раза. C11 n1570 6.7.3p5:
If the same qualifier appears more than once in the same specifier-qualifier-list, either directly or via one or more typedefs, the behavior is the same as if it appeared only once.
то есть то, что -Wduplicate-decl-specifier не является ошибкой как таковой, но такой код дословно является подозрительный - должно ли это быть volatile int *volatile, которое было написано с ошибкой как volatile int volatile *, что привело к тому, что указатель был неквалифицированным...
Квалификаторы применяются к типу левого осталось квалификатора, за исключением случаев, когда сам квалификатор является самым левым, и в этом случае он как если бы он был справа от базового типа, т.е.
volatile int *
а также
int volatile *
означает одно и то же. Поэтому в volatile int volatile вы можете удалить один из них. Таким образом, то, что вам нужно, это
volatile int *volatile vipa[10];
Это означает, что vipais an array of 10volatile-qualified pointers tovolatileint`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:
EXAMPLE The following pair of declarations demonstrates the difference between a ''variable pointer to a constant value'' and a ''constant pointer to a variable value''.
const int *ptr_to_constant; int *const constant_ptr;The contents of any object pointed to by
ptr_to_constantshall not be modified through that pointer, butptr_to_constantitself may be changed to point to another object. Similarly, the contents of theintpointed to byconstant_ptrmay be modified, butconstant_ptritself shall always point to the same location.
Кроме того, можно добавить квалификатор типа для множество в скобках, но только в параметрах функции, поэтому вы можете написать
void foo(int array[volatile])
что означает почти то же самое, и параметр распадается на квалифицированный указатель
void foo(int *volatile array)
но вы можете использовать спецификатор static только с прежним стилем.
Тот факт, что массив не может быть квалифицирован, не связан с тем, что его адрес является постоянным. Каждый объект имеет постоянный адрес. Причина, по которой квалификаторы применяются к элементам, а не к массивам, заключается в том, что массив никогда нельзя использовать в качестве объекта так, как квалификаторы применялись бы.
объяснение простое.
volatile int * == int volatile *
в этом случае порядок не имеет значения.
Так что volatile int * volatile x; == int volatile * volatile x;
если у вас есть volatile int volatile * вы уже объявили его как volatile, второй не нужен
Спасибо! Просто убедитесь, что я правильно понимаю эту часть. «Если спецификация типа массива включает какие-либо квалификаторы типа ...» - это, по сути, последнее предложение в вашем ответе, верно? Выглядит ли «спецификация типа массива, включающая квалификаторы», как последнее объявление в ответе?