Являются ли оба этих использования квалификатора volatile избыточными?

Рассмотреть возможность

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 в этом отношении, пожалуйста, сделайте пометку.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
153
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

TL;DR:

  • In (1), do the 1st and 2nd volatile qualifiers both refer to int, 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 not the 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:

  1. 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_constant shall not be modified through that pointer, but ptr_to_constant itself may be changed to point to another object. Similarly, the contents of the int pointed to by constant_ptr may be modified, but constant_ptr itself shall always point to the same location.


Кроме того, можно добавить квалификатор типа для множество в скобках, но только в параметрах функции, поэтому вы можете написать

void foo(int array[volatile])

что означает почти то же самое, и параметр распадается на квалифицированный указатель

void foo(int *volatile array)

но вы можете использовать спецификатор static только с прежним стилем.

Спасибо! Просто убедитесь, что я правильно понимаю эту часть. «Если спецификация типа массива включает какие-либо квалификаторы типа ...» - это, по сути, последнее предложение в вашем ответе, верно? Выглядит ли «спецификация типа массива, включающая квалификаторы», как последнее объявление в ответе?

iksemyonov 22.04.2019 14:02

Тот факт, что массив не может быть квалифицирован, не связан с тем, что его адрес является постоянным. Каждый объект имеет постоянный адрес. Причина, по которой квалификаторы применяются к элементам, а не к массивам, заключается в том, что массив никогда нельзя использовать в качестве объекта так, как квалификаторы применялись бы.

Eric Postpischil 22.04.2019 14:53

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

volatile int * == int volatile *

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

Так что volatile int * volatile x; == int volatile * volatile x;

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

Другие вопросы по теме