Массивы с нулевой длиной
Недавно я столкнулся с определением структуры,
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]
недействителен.