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.
Далее: Пустые структуры, Предыдущее: Имена адресных пространств, Вверх: Расширения языка C [Оглавление][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Zero-Length.html