我不明白为什么
struct e{
void * a;
void * b[];
}
有sizeof(e)== 4而
struct f{
void * a;
void * b;
}
sizeof(f)== 8.
答案 0 :(得分:17)
struct e{
void * a;
void * b[];
// ^^
}
结构中的[]
使b
成为C99“灵活数组成员”。因此,sizeof(e)
将仅计算a
的大小,即4。
来自C99§6.7.2.1/ 16:
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这称为灵活数组成员。在大多数情况下,将忽略灵活数组成员。 特别是,结构的大小就好像省略了柔性阵列成员,除了它可能具有比遗漏意味着更多的尾随填充。
但是,当
.
(或->
)运算符的左操作数(指向)具有灵活数组成员且右操作数命名该成员的结构时,其行为如下如果该成员被替换为最长的数组(具有相同的元素类型),该数组不会使结构大于被访问的对象;数组的偏移量应保持为灵活数组成员的偏移量,即使这与替换数组的偏移量不同。如果此数组没有元素,则其行为就好像它有一个元素,但如果尝试访问该元素或生成一个超过它的指针,则行为是未定义的。
答案 1 :(得分:12)
第一个结构中的第二个不是指针,而是FAM - 灵活的数组成员。当您有一个长缓冲区并在该缓冲区的开头放置e
时使用它。然后,您可以使用该FAM索引e
对象后面的剩余内存,并将该内存视为void*
的数组。
标准说(由我强调)
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可以 有一个不完整的数组类型;这被称为灵活的阵列成员。在大多数情况下, fl exible数组成员被忽略。 特别是,结构的大小就像是 省略了灵活的数组成员,除了它可能有更多的尾随填充 遗漏意味着。
例如,以下代码为结构输出1
,但4
用于GCC上具有FAM的结构,因为要访问整数,FAM需要正确对齐(在4上本例中的字节边界)
struct A {
char a;
};
struct B {
char a;
int flex[];
};
int main() {
printf("sizeof A: %d\nsizeof B: %d\n",
(int)sizeof(struct A),
(int)sizeof(struct B)
);
struct B *b = malloc(sizeof *b + sizeof(int[3]));
b->a = 'X';
b->flex[0] = 1;
b->flex[1] = 2;
b->flex[2] = 3;
free(b);
}
答案 2 :(得分:2)
这是因为第二个结构使用灵活成员数组。结果sizeof的说明位于Wikipedia。
答案 3 :(得分:1)
void * b[];
在C89
中无效,因此这意味着您正在使用C99
编译器。
C99
引入了一种定义“struct hack”的方法:它现在被称为“灵活的数组成员”,在它被分配内存之前,它的大小为0。
答案 4 :(得分:0)
因为第一个没有为“b”中的指针声明任何空格。