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

时间:2015-03-30 19:39:07

标签: 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);
}

2 个答案:

答案 0 :(得分:7)

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

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

  

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

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

  

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

从一些快速实验中,GCC和Clang都添加了正确对齐FAM所需的尾随填充,即使struct是嵌套的,并且仅警告FAM构成其他结构或数组的结构{} {{ 1}}被传递,所以把它作为一个标志,如果你愿意它可能会工作:)。虽然感觉有些迟钝。

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

-Wpedantic

,然后struct e { struct d d; int n; } e; e.d.ns[0]可能在内存中重叠。

答案 1 :(得分:0)

尝试这样的事情;

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);
}