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-5.5.0/gcc/Zero-Length.html