6.18 Массивы нулевой длины
Объявление массивов нулевой длины разрешено в GNU C в качестве расширения. Массив нулевой длины может быть полезен как последний элемент структуры, которая на самом деле является заголовком для объекта переменной длины:
struct line {
int length;
char contents[0];
};
struct line *thisline = (struct line *)
malloc (sizeof (struct line) + this_length);
thisline->length = this_length;
Хотя размер массива нулевой длины равен нулю, член массива такого типа может увеличить размер содержащего типа в результате добавления хвостового заполнения. Смещение элемента массива нулевой длины от начала содержащей структуры такое же, как и смещение массива с одним или несколькими элементами того же типа. Выравнивание массива нулевой длины такое же, как выравнивание его элементов.
Объявление массивов нулевой длины в других контекстах, включая внутренние члены объектов структуры или как объекты, не являющиеся членами, не рекомендуется. Доступ к элементам массивов нулевой длины, объявленных в таких контекстах, не определён и может быть диагностирован.
В отсутствие расширения массивов нулевой длины в ISO C90 массив contents в примере выше обычно объявлялся бы с одним элементом. В отличие от массива нулевой длины, который влияет только на размер содержащей структуры с точки зрения выравнивания, массив с одним элементом всегда занимает по крайней мере столько же места, сколько и один объект типа. Хотя использование массивов с одним элементом таким образом не рекомендуется, GCC обрабатывает доступ к элементам массивов с одним элементом, расположенным в конце, аналогично массивам нулевой длины.
Предпочтительный механизм для объявления типов переменной длины, таких как struct line выше, это гибкий член массива ISO C99, с немного другой синтаксисом и семантикой:
- Гибкие члены массива записываются как
contents[]без0. - Гибкие члены массива имеют неполный тип, поэтому оператор
sizeofне может быть применён. Как особенность оригинальной реализации массивов нулевой длины,sizeofоценивается как ноль. - Гибкие члены массива могут появляться только в качестве последнего члена
structструктуры, которая в ином случае не пуста. - Структура, содержащая гибкий член массива, или объединение, содержащее такую структуру (возможно, рекурсивно), не может быть членом структуры или элементом массива. (Однако эти использования разрешены GCC как расширения.)
Непустое инициализирование массивов нулевой длины обрабатывается так же, как и в любом случае, когда количество элементов инициализатора больше, чем может вместить массив, в том смысле, что выдаётся соответствующее предупреждение о «лишних элементах в массиве», а лишние элементы (все они, в данном случае) игнорируются.
GCC позволяет статическую инициализацию гибких членов массива. Это эквивалентно определению новой структуры, содержащей исходную структуру, за которой следует массив достаточного размера для хранения данных. Например, в следующем f1 создаётся как если бы он был объявлен как f2.
struct f1 {
int x; int y[];
} f1 = { 1, { 2, 3, 4 } };
struct f2 {
struct f1 f1; int data[3];
} f2 = { { 1 }, { 2, 3, 4 } };
Удобство этого расширения заключается в том, что f1 имеет желаемый тип, устраняя необходимость постоянной ссылки на f2.f1.
Это имеет симметрию с обычными статическими массивами, так как массив неизвестного размера также записывается с [].
Конечно, это расширение имеет смысл только если дополнительные данные добавляются в конец верхнего объекта, иначе мы бы перезаписывали данные по последующим смещениям. Для избежания излишней сложности и путаницы с инициализацией глубоко вложенных массивов мы просто запрещаем любую непустую инициализацию, за исключением случая, когда структура является верхним объектом. Например:
struct foo { int x; int y[]; };
struct bar { struct foo z; };
struct foo a = { 1, { 2, 3, 4 } }; // Valid.
struct bar b = { { 1, { 2, 3, 4 } } }; // Invalid.
struct bar c = { { 1, { } } }; // Valid.
struct foo d[1] = { { 1, { 2, 3, 4 } } }; // Invalid.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-13.3.0/gcc/Zero-Length.html