Член гибкого массива во вложенной структуре
Это допустимый код C, чтобы иметь гибкие члены массива внутри вложенных структур? Так гарантированно ли мой пример кода ниже для нормальной работы компилятора?
#include <stdio.h>
#include <stdlib.h>
struct d {
char c;
int ns[];
};
struct c {
struct d d;
};
struct b {
struct c c;
};
struct a {
int n;
struct b b;
};
int main() {
const int n = 10;
struct a *pa = malloc(sizeof(*pa) + n * sizeof(pa->b.c.d.ns[0]));
pa->n = n;
pa->b.c.d.c = 1;
for (int i = 0; i < n; ++i) {
pa->b.c.d.ns[i] = i;
}
for (int i = 0; i < n; ++i) {
printf("%d\n", pa->b.c.d.ns[i] + pa->b.c.d.c);
}
free(pa);
}
1 ответ
Это не действует в соответствии со стандартом. Я не уверен, насколько это надежно на практике.
C11 (ISO / IEC 9899: 2011), §6.7.2.1.3, говорит следующее (выделено мной):
Структура или объединение не должны содержать члена с неполным или функциональным типом (следовательно, структура не должна содержать своего экземпляра, но может содержать указатель на свой экземпляр), за исключением того, что последний член структуры с более чем один именованный член может иметь неполный тип массива; такая структура (и любое объединение, содержащее, возможно, рекурсивно член, являющийся такой структурой) не должно быть членом структуры или элементом массива.
Позже, §6.7.2.1.18 поясняет, что вышесказанное относится к гибким элементам массива (FAM):
В особом случае последний элемент структуры с более чем одним именованным элементом может иметь тип неполного массива; это называется членом гибкого массива.
После нескольких быстрых экспериментов GCC и Clang добавляют завершающий отступ, необходимый для правильного выравнивания FAM, даже когда struct
является вложенным и предупреждает о структурах, в которых FAM являются членами других структур или массивов, если -Wpedantic
пропущено, так что воспринимайте это как знак того, что это, вероятно, сработает, если хотите:) Это кажется немного хакерским, хотя.
Обратите внимание, что, вероятно, не имеет смысла иметь FAM где-нибудь, кроме как в конце. Если вы делаете
struct e {
struct d d;
int n;
} e;
, затем e.d.ns[0]
а также e.n
могут перекрываться в памяти.
Попробуйте что-то вроде этого;
struct d {
char c;
int ns[];
};
struct a {
int n;
int d_fam[];
};
int main() {
const int n = 10;
struct a *pa = malloc(offsetof (struct a, d_fam) + offsetof (stuct d, ns) + n * sizeof(int));
struct d *pd = pa + (uintptr_t) offsetof (struct a, d_fam);
pa->n = n;
pd->c = 1;
for (int i = 0; i < n; ++i) {
pd->ns[i] = i;
}
for (int i = 0; i < n; ++i) {
printf ("%d\n", pd->ns[i] + pd->c);
}
free(pa);
}