Массивы с нулевой длиной

Недавно я столкнулся с определением структуры,

struct arr {
    int cnt;
    struct {
        int  size;
        int *name;
    } list[0];
};

и теперь я не знаю причины объявления list[0]. Меня интересует, почему это используется. Имеет ли он какое-либо преимущество? Если да, что это?

Ответ 1

Используется для массивов с динамической длиной. Вы можете выделить память с помощью malloc() и иметь массив в конце структуры:

struct arr *my_arr = malloc(sizeof *my_arr + 17 * sizeof *my_arr->list);
my_arr->cnt = 17;
my_arr->list[0].size = 0;
my_arr->list[1].name = "foo";

Фактически, возможность использования 0 для длины (как указано в комментарии) является расширением GCC. В C99 вы можете полностью исключить литерал размера для того же эффекта.

Прежде чем эти вещи были реализованы, вы часто видели, что это сделано с длиной 1, но это немного усложняет выделение, поскольку вы должны компенсировать необходимость вычисления необходимой памяти.

Ответ 2

Он называется "struct hack" . Вы можете найти его на SO или в сети.

http://www.google.com/search?q=struct+hack&sitesearch=stackoverflow.com/questions

Обратите внимание, что формально всегда запрещено объявлять массивы размером 0 в C. Код, который вы предоставили формально, даже не поддается компиляции. Большинство компиляторов C будут принимать объявление массива 0-размера как расширение, особенно потому, что оно часто используется в "ленивой" версии "struct hack" (он может полагаться на sizeof, чтобы определить, сколько памяти выделяется, поскольку 0- размер массива, предположительно, не влияет на общий размер структуры).

Вероятно, лучшая реализация struct hack использует массив размером 1

struct arr {
    int cnt;
    struct {
        int  size;
        int *name;
    } list[1];
};

Он "лучше", потому что он формально компилируется, по крайней мере. Чтобы выделить память для структуры с элементами N в list, используется стандартный макрос offsetof

arr *a = malloc(offsetof(arr, list) + N * sizeof a->list);

В версии спецификации языка C99 "struct hack" поддерживается в объявлении массива без размера (с пустым []), так как объявления с размером 0-го разряда также являются незаконными на C99.

Ответ 3

Другим преимуществом является то, что ваша структура описывает данные на диске/в сети. Если cnt равно 0, размер данных может быть только длиной cnt.

Я здесь, чтобы подтвердить, что я боялся, что list[0] недействителен.