Spec-Zone.ru › GCC 10

Следующая: Структуры без членов, Предыдущая: Пространства имён адресов, Вверх: Расширения для семейства языков C [Оглавление][Индекс]

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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API