嵌套结构中的灵活数组成员

xiv*_*r77 4 c struct flexible-array-member

在嵌套结构中有灵活的数组成员是有效的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);
}
Run Code Online (Sandbox Code Playgroud)

Ulf*_*zer 7

根据标准,它无效.我不确定它在实践中有多可靠.

C11(ISO/IEC 9899:2011),§6.7.2.1.3说明以下(强调我的):

结构或联合不应包含具有不完整或函数类型的成员(因此,结构不应包含其自身的实例,但可以包含指向其自身实例的指针),除了结构的最后一个成员具有多个一个命名成员可能有不完整的数组类型; 这样的结构(以及可能递归地包含这种结构的成员的任何联合)不应是结构的成员或数组的元素.

后来,§6.7.2.1.18阐明了上述内容是指灵活的阵列成员(FAM):

作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; 这被称为灵活的阵列成员.

从一些快速实验中,GCC和Clang都添加了即使在struct嵌套时也能正确对齐FAM所需的尾随填充,并且仅警告关于FAM是其他结构或数组的成员的结构(如果-Wpedantic通过),所以将其作为标志如果你愿意,它可能会工作:).虽然感觉有点hackish.

请注意,将FAM放在任何地方但最后都没有意义.如果你这样做

struct e {
    struct d d;
    int n;
} e;
Run Code Online (Sandbox Code Playgroud)

,那么e.d.ns[0]并且e.n很可能在记忆中重叠.