根据Wikipedia:
最后一个成员填充所需的字节数,以便结构的总大小应该是任何结构成员的最大对齐的倍数
根据我的理解,这意味着以下内容:
struct A {
char *p; // 8 bytes
char c; // 1 byte
};
struct B {
struct A a; // 16 bytes
char d; // 1 bytes
};
struct A
的大小为16个字节,struct B
的大小为24个字节。
常见的解释是A
的数组应该可以在数组的地址访问它们的元素,加上索引的大小为A
。
但我不明白为什么会这样。为什么我们不能说A
的大小为9而B
的大小为10(两个字节对齐),并且在索引到数组时使用特殊的“数组存储”大小?
当然,我们仍然以与其对齐兼容的方式将这些类型存储在数组中(使用16个字节来存储每个B
元素)。然后,我们只是通过考虑它们的对齐来计算元素地址,而不是单独考虑它们的大小(编译器可以静态地执行)。
例如,我们可以在B
的1Kb字节数组中存储64个对象,而不是仅存储42个。
答案 0 :(得分:1)
在C的每个翻译单元中,无论sizeof(T)
的上下文如何,T
都是相同的。您的提案会为sizeof(T)
引入至少两个值:一个用于T
的数组,另一个用于T
的单个对象。这基本上将上下文依赖引入sizeof
运算符。它与C处理指针,数组和对象地址的方式不兼容。
请考虑以下事项:
void zero_A(struct A *a) { memset(a,0,sizeof(*a)); }
/* ... */
struct A single;
struct A several[3];
struct B b;
b.d = 3;
zero_A(&b.a);
zero_A(&single);
zero_A(several+1);
根据您的提案,zero_A
必须知道传递的指针是否指向数组上下文中的struct A
(sizeof(*a) == 16
}或struct A
之外的数组上下文(其中sizeof(*a) == 9
)。标准C不支持此功能。如果编译器猜错了,或者信息丢失了(例如:在volatile struct A *
的往返中),那么zero_A(&single)
将调用未定义的行为(通过写single
的边界),zero_A(&b.a)
将覆盖b.d
并调用未定义的行为。
将结构紧密地打包到数组中是一个相对不常见的要求,并且向sizeof
添加上下文依赖会给语言,库和ABI带来许多复杂性。有时您需要这样做,C为您提供所需的工具:memcpy
和工会。