6.29 Инициализаторы с указанием ¶
Стандарт C90 требует, чтобы элементы инициализатора появлялись в фиксированном порядке, совпадающем с порядком элементов массива или структуры, которые инициализируются.
В ISO C99 вы можете указывать элементы в любом порядке, задавая индексы массива или имена полей структуры, к которым они относятся, и GNU C позволяет это в режиме C90 также как расширение. Это расширение не реализовано в GNU C++.
Чтобы указать индекс массива, запишите ‘[индекс] =’ перед значением элемента. Например,
int a[6] = { [4] = 29, [2] = 15 };
эквивалентно
int a[6] = { 0, 0, 15, 0, 29, 0 };
Значения индексов должны быть константными выражениями, даже если массив, который инициализируется, является автоматическим.
Альтернативный синтаксис для этого, который устарел с GCC 2.5, но все еще принимается GCC, — это запись ‘[индекс]’ перед значением элемента без ‘=’.
Чтобы инициализировать диапазон элементов одним и тем же значением, запишите ‘[первый ... последний] = значение’. Это расширение GNU. Например,
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
Если значение в нем имеет побочные эффекты, побочные эффекты происходят только один раз, а не для каждого инициализированного поля с помощью инициализатора диапазона.
Обратите внимание, что длина массива — это наибольшее указанное значение плюс один.
В инициализаторе структуры укажите имя поля, которое нужно инициализировать, с помощью ‘.имя_поля =’ перед значением элемента. Например, с учетом следующей структуры,
struct point { int x, y; };
следующая инициализация
struct point p = { .y = yvalue, .x = xvalue };
эквивалентна
struct point p = { xvalue, yvalue };
Другой синтаксис, имеющий то же значение, устаревший с GCC 2.5, — это ‘имя_поля:’, как показано здесь:
struct point p = { y: yvalue, x: xvalue };
Пропущенные поля неявно инициализируются так же, как и объекты, имеющие статическую длительность хранения.
‘[индекс]’ или ‘.имя_поля’ называется обозначением. Вы также можете использовать обозначение (или устаревший синтаксис с двоеточием) при инициализации объединения, чтобы указать, какой элемент объединения следует использовать. Например,
union foo { int i; double d; };
union foo f = { .d = 4 };
преобразует 4 в double для хранения в объединении, используя второй элемент. В отличие от этого, преобразование 4 к типу union foo хранит его в объединении как целое число i, так как это целое число. См. Преобразование к типу объединения.
Вы можете сочетать этот метод именования элементов с обычной C-инициализацией последовательных элементов. Каждый элемент инициализатора, не имеющий обозначения, относится к следующему последовательному элементу массива или структуры. Например,
int a[6] = { [1] = v1, v2, [4] = v4 };
эквивалентно
int a[6] = { 0, v1, v2, 0, v4, 0 };
Именование элементов инициализатора массива особенно полезно, когда индексы являются символами или относятся к типу enum. Например:
int whitespace[256]
= { [' '] = 1, ['\t'] = 1, ['\h'] = 1,
['\f'] = 1, ['\n'] = 1, ['\r'] = 1 };
Вы также можете записать серию ‘.имя_поля’ и ‘[индекс]’ обозначений перед ‘=’ для указания вложенного подобъекта для инициализации; список берется относительно подобъекта, соответствующего ближайшей окружающей паре фигурных скобок. Например, с объявлением ‘struct point’ выше:
struct point ptarray[10] = { [2].y = yv2, [2].x = xv2, [0].x = xv0 };
Если одно и то же поле инициализируется несколько раз или перекрывающиеся поля объединения инициализируются, используется значение от последней инициализации. Если поле объединения само по себе является структурой, используется вся структура из последнего инициализированного поля. Если любой предыдущий инициализатор имеет побочный эффект, не определено, произойдет ли побочный эффект или нет. В настоящее время GCC отбрасывает выражения инициализатора с побочными эффектами и выдает предупреждение.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-11.4.0/gcc/Designated-Inits.html