分配具有柔性数组成员的结构体

7

这是C99代码:

typedef struct expr_t
{
    int n_children; 
    foo data; // Maybe whatever type with unknown alignment
    struct expr_t *children[];
} expr_t;

现在,我该如何分配内存?
expr_t *e = malloc (sizeof (expr_t) + n * sizeof (expr_t *));

或者

expr_t *e = malloc (offsetof (expr_t, children) + n * sizeof (expr_t *));
< p> < 代码> sizeof < p> 在具有灵活数组成员的类型上工作是否有保障(GCC接受它)?

3
是的,它保证有效。C99 §6.7.2.1/16规定:“结构体的大小应等于将柔性数组成员替换为未指定长度的数组时,最后一个元素的偏移量”。因此,如果您将children重新定义为任何确定大小的数组,则sizeof(expr_t)的值将等于offsetof(expr_t, children)的值。 - Adam Rosenfield
2个回答

11

expr_t *e = malloc (sizeof (expr_t) + n * sizeof (expr_t *));在C99标准中定义良好。根据C99规范6.7.2.1.16:

作为特例,具有多个命名成员的结构的最后一个元素可以具有不完整的数组类型;这称为柔性数组成员。在大多数情况下,忽略柔性数组成员。特别地,结构体的大小就像省略了柔性数组成员一样,只是它可能会比省略要求的多一些尾部填充。


4
如果编译器接受具有灵活数组成员的结构体的声明,那么该结构体的sizeof操作符应该将该结构体的大小作为结果返回,就好像灵活数组成员不存在一样。
这样的结构体正确的分配方式是:
expr_t *e = malloc (sizeof(expr_t) + n * sizeof(struct expr_t *));

即使编译器不支持灵活数组成员,您仍然可以使用这个技巧。只需将结构体的数组成员声明为大小为1的数组,然后分配n-1项而不是n项即可。请注意保留HTML标记。

3
小小的警告:一个结构体的填充/对齐要求将由最严格的元素决定;一个具有更严格对齐要求的灵活数组元素,可能会改变结构体的填充和对齐方式。例如,在一些机器上,一个包含一个char和一个float[]的结构体可能是4个字节并需要4字节对齐,即使没有double[]的情况下它只有1个字节。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接