结构中的成员的顺序是否重要?
我在C中发现了一个奇特的行为。考虑下面的代码:
struct s { int a; }; struct z { int a; struct sb[]; }; int main(void) { return 0; }
它编译得很好。 然后像这样改变struct z
成员的顺序
struct z { struct sb[]; int a; };
突然之间,我们得到的编译错误field has incomplete type 'struct s []'
。
这是为什么?
struct
中字段的顺序很重要 – 编译器不允许对字段重新sorting,所以struct
的大小可能会因添加一些填充而改变。
然而在这种情况下,你正在定义一个所谓的灵活的成员 ,一个你可以改变大小的数组。 灵活的成员规则是这样的
- 可能永远不会有一个以上的这样的成员,
- 如果存在,灵活的成员必须是结构中的最后一个,并且
- 该
struct
必须至less有一个成员除了灵活的一个。
看一下这个问答关于使用灵活的结构成员的小插图。
编译器不能计算多less内存struct sb[];
会消耗。 这意味着如果结构体之后有任何字段,编译器就无法弄清楚这些字段在哪里。
它曾经是(在旧版本的C),(例如) struct sb[];
不被允许作为一个结构的成员。 这使得高效的内存pipe理变得烦人。 举一个简单的例子,假设你有一个包含“name”string的结构(可能只是几个字符或者很多)。 你可以使用一个固定大小的数组,这个数组对于最大的名字是足够大的(浪费空间),或者使用一个指针并分配2个内存(一个用于结构,另一个用于可变长度名string)。 或者,你可以使用一个指针,并使其指向结构末端的额外空间,结果如下所示:
length = strlen(my_string); foo = malloc(sizeof(MYSTRUCTURE) + length + 1); foo->name = (void *)foo + sizeof(MYSTRUCTURE); // Set pointer to extra bytes past end of structure memcpy(foo->name, my_string, length + 1);
这是最有效的select; 但它也是丑陋的和容易出错的。
为了解决这个问题,编译器添加了非标准的扩展以允许在结构的末尾使用“未知大小的数组”。 这对程序员来说更简单一些,并且使其效率更高一些(因为不需要额外的指针成员)。 这最终被C标准采用(可能在C99中 – 我不记得了)。
成员的顺序通常很重要(即可能会在字段之间插入一些填充),但在具体情况下,您使用的是灵活的成员数组,这在C99-6.7.2.1.16
作为特殊情况,具有多个名称成员的结构的最后一个元素可能具有不完整的数组types; 这被称为一个灵活的数组成员。 在大多数情况下,灵活的数组成员被忽略。 特别是,结构的大小就好像是柔性arrays成员被省略,除了它可能具有比省略暗示的更多的尾部填充。
你的struct sb[];
成员是用来访问多个struct s
元素的dynamic堆分配。
你的问题的标题是“ struct
的成员的顺序是否重要?”。
代码中的明显问题与您的struct
包含灵活成员的事实有关。
所以这是一个与struct
中成员顺序的一般问题有关的额外问题:
以下面两个结构为例:
struct s1 { int a; short b; char c; }; struct s2 { char c; short b; int a; };
大多数编译器都会添加填充,以便将每个成员alignment到可以被大小整除的地址。
所以struct s2
最终可以编译成:
struct s2 { char c; char pad1; short b; short pad2; short pad3; int a; };
这最终将导致types为struct s1
和struct s2
实例的大小不同。
在这种情况下,订单确实很重要。 你的struct z
包含一个由structs s
struct z
组成的数组。 但是,这个数组没有与它相关的大小,所以编译器不知道如何分配适当的堆栈空间,因为之后还有另一个struct( int a
)字段。 一个如何工作的例子:
struct s { int a; } struct z { struct sb[10]; int a; } int main(void) { return 0; }
如果你真的需要数组来改变大小,最好的办法是把整个结构分配给堆,把数组作为struct s
的指针,然后dynamic地重新分配它以适应不断变化的数组大小。 查找malloc (3)
, realloc 3)
, calloc (3)
和free (3)
。