Какова цель появления ключевого слова volatile внутри индекса массива?


Когда я просматривал cppreference, я увидел странный массив типа в параметрах функции, таких как:

void f(double x[volatile], const double y[volatile]);

Итак, какова цель появления ключевого слова volatile внутри подстрочного индекса массива? Что он делает?

2 42

2 ответа:

Ключевое слово

Используется для объявления типа массива параметра функции.

Здесь double x[volatile] эквивалентно double * volatile x.

В cppreference говорится :

В объявлении функции, ключевое слово volatile может появиться внутри квадратные скобки, используемые для объявления типа массива функции параметр. он определяет тип указателя, к которому относится тип массива преобразованный. Следующие два объявления объявляют то же самое функция:

void f(double x[volatile], const double y[volatile]);

void f(double * volatile x, const double * volatile y);

Этот синтаксис допустим только в языке Си в параметрах функции.

В общем, это С (и только с!) функция позволяет указать любой тип квалификатора внутри скобок массива; точная стандартная цитата:

Объявление параметра в виде "массива типа" должно быть изменено на " квалифицированный указатель на type", , где квалификаторами типа (если таковые имеются) являются те, которые указаны в [ и ] вывод типа массива . Если ключевое слово static также появляется в пределах [ и ] вывод типа массива, затем для каждого вызова функции значение соответствующего фактический аргумент должен обеспечивать доступ к первому элементу массива с не меньшим числом аргументов. элементы, заданные выражением размера.

(C99, §6.7.5.3, ¶7, курсив добавлен)

Это означает, что это не ограничивается только volatile, но const и restrict также разрешены (см. квалификаторы типов, §6.7.3 ¶1).

Суть этого хака состоит в том, чтобы позволить вам добавить квалификатор типа к параметру (не к элементу массива) и все еще сохраняют синтаксис массива для объявления; без этого синтаксиса вы вынуждены вернуться к записи его в виде указателя (что в любом случае сводится к , за исключением случая static , в котором AFAIK не имеет эквивалентного синтаксиса указателя).

Я подозреваю, что идея заключается в том, чтобы сделать синтаксис немного менее неудобным для многомерных массивов; цитируя §6.7.5.3 *21:

void f(double (* restrict a)[5]);
void f(double a[restrict][5]);
void f(double a[restrict 3][5]);

Все эквивалентны, но 2 и 3 могут немного лучше передать, что это не просто указатель, а массив, и все же позволяет поместить в некотором месте квалификатор restrict.

Кроме того, как было сказано выше, кажется, нет никакого способа иметь что-то вроде

void f(double a[restrict static 3][5]);

(который "также указывает, что аргумент, соответствующий a в любом вызове f, должен быть ненулевым указателем на первый из по крайней мере трех массивов из 5 двойников", ibidem ) с "обычный" синтаксис указателя.

Тем не менее, я бы держался подальше от этого синтаксиса; он крайне неясен, редко используется (я не думаю, что мне когда - либо нужно было добавлять квалификатор типа в массив параметр - опять же, сам параметр, а не тип элемента; restrict - единственный вариант использования, который может иметь смысл) - и не переносится на C++ (что обычно актуально, если вы пишете библиотеку).