Являются ли оба эти изменчивых использования квалификатора избыточными? - PullRequest
5 голосов
/ 22 апреля 2019

Рассмотрим

volatile int volatile * volatile vip; // (1)

и

volatile int volatile * volatile vipa[10]; // (2)

Обе строки кода запускают -Wduplicate-decl-specifier (см. rev 236142 и gcc7 Замечания по выпуску ). Я хотел бы знать, смогу ли я удалить некоторые спецификаторы volatile из данного кода, не изменяя семантику кода, и понять причины, стоящие за этим.

Итак, следующие вопросы:

а . В (1) оба квалификатора 1-го и 2-го volatile относятся к int, таким образом, являясь «дубликатами» в терминах gcc? (Я смотрю на C99 6.7.3.4 здесь.)

б . В (2) один из квалификаторов volatile ссылается на тип массива, а не на int или сам указатель, так что C99 6.7.3.8 содержит:

Если спецификация типа массива включает какие-либо квалификаторы типа, тип элемента является таким, а не тип массива.

или спецификаторы volatile в (2) влияют только на тип int и pointer, а не на тип массива?

с . Если ответ на b отрицательный, как мне объявить тип массива volatile, который описан в C99 6.7.3.8? Это синтаксис, описанный в https://en.cppreference.com/w/c/language/array (цитата следует)?

квалификаторы - любая комбинация квалификаторов const, restrict или volatile, допускается только в списках параметров функции; это определяет тип указателя, в который преобразуется этот параметр массива

Давайте рассмотрим вопрос о С99. Если есть какие-либо различия в C11 в этом отношении, пожалуйста, запишите.

Ответы [ 2 ]

5 голосов
/ 22 апреля 2019

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 :

  1. ПРИМЕР Следующая пара объявлений демонстрирует разницу между '' указателем переменной на постоянное значение '' и '' указателем константы на значение переменной ''.

    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 только с прежним стилем.

4 голосов
/ 22 апреля 2019

объяснение простое.

volatile int * == int volatile *

в этом случае порядок не имеет значения.

Итак volatile int * volatile x; == int volatile * volatile x;

если у вас есть volatile int volatile *, вы уже объявили его как volatile, второй не нужен

...