Пока я просматривал cppreference, я видел в параметрах функции вроде странного типа:
void f(double x[volatile], const double y[volatile]);
Итак, Какова цель ключевого слова volatile
, появляющегося внутри индекса массива? Что он делает?
Пока я просматривал cppreference, я видел в параметрах функции вроде странного типа:
void f(double x[volatile], const double y[volatile]);
Итак, Какова цель ключевого слова volatile
, появляющегося внутри индекса массива? Что он делает?
Ключевое слово volatile
используется для объявления типа массива параметра функции.
Здесь 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);
Этот синтаксис действителен только на языке C в параметрах функции.
В общем, эта функция C (и C only!) позволяет указать любой классификатор типа внутри скобок массива; точная стандартная цитата:
Объявление параметра как '' массива типа должно быть скорректировано на '' квалифицированный указатель на 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
- единственный случай, который может иметь смысл) - и не переносится на С++ (что обычно имеет значение, если вы пишете библиотеку).