Spec-Zone.ru › GCC 6

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

Spec-Zone.ru

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