我在C中发现了一种奇特的行为.请考虑以下代码:
struct s {
int a;
};
struct z {
int a;
struct s b[];
};
int main(void) {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它编译得很好.然后z
像这样改变struct成员的顺序
struct z {
struct s b[];
int a;
};
Run Code Online (Sandbox Code Playgroud)
突然间,我们得到了编译错误field has incomplete type 'struct s []'
.
这是为什么?
Bre*_*dan 21
编译器无法计算struct s b[];
将消耗多少内存.这意味着如果结构后面有任何字段,编译器就无法确定这些字段的位置.
过去(在旧版本的C中)(例如)struct s b[];
不允许作为结构的成员.这使得高效的内存管理变得烦人.举一个简单的例子,假设你有一个包含"name"字符串的结构(可能只是几个字符或很多字符).您可以使用固定大小的数组,该数组足以容纳最大的名称(浪费空间),或者使用指针并分配2个内存(一个用于结构,一个用于可变长度名称字符串).或者,您可以使用指针并使其指向结构末尾之外的额外空间,最终会出现如下情况:
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);
Run Code Online (Sandbox Code Playgroud)
这是最有效的选择; 但它也很丑陋且容易出错.
为了解决这个问题,编译器添加了非标准扩展,以允许在结构的末尾使用"未知大小的数组".这使程序员更容易一些,并使其更高效(因为不需要额外的指针成员).这最终被C标准采用(也许在C99 - 我不记得了).
Mar*_* A. 15
成员的顺序通常很重要(即某些填充可能插入字段之间),但在您的特定情况下,您使用的是灵活的成员数组,这在C99中是标准化的 - 6.7.2.1.16
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; 这被称为灵活的阵列成员.在大多数情况下,将忽略灵活数组成员.特别地,结构的尺寸好像省略了柔性阵列构件,除了它可以具有比省略意味着更多的拖尾填充.
您的struct s b[];
成员旨在用于访问多个struct s
元素的动态堆分配.
你的问题的标题是“成员的顺序有struct
问题吗?”。
您代码中的明显问题与您struct
包含一个灵活成员的事实有关。
因此,这里有一个与 a 中成员顺序的一般问题相关的附加问题struct
:
以下面两种结构为例:
struct s1
{
int a;
short b;
char c;
};
struct s2
{
char c;
short b;
int a;
};
Run Code Online (Sandbox Code Playgroud)
大多数编译器会添加填充,以便将每个成员与可被其大小整除的地址对齐。
所以struct s2
可能最终编译成:
struct s2
{
char c;
char pad1;
short b;
short pad2;
short pad3;
int a;
};
Run Code Online (Sandbox Code Playgroud)
这最终将导致类型struct s1
和struct s2
.