Spec-Zone.ru › GCC 9

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

Spec-Zone.ru

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