6.17 Массивы нулевой длины
Массивы нулевой длины разрешены в 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 длину 1, что означает либо потерю места, либо усложнение аргумента для malloc.
В 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-7.5.0/gcc/Zero-Length.html