根据 Wikipedia :
the last member is padded with the number of bytes required so that the total size of the structure should be a multiple of the largest alignment of any structure member
在我的理解中,它的意思是:
struct A {
char *p; // 8 bytes
char c; // 1 byte
};
struct B {
struct A a; // 16 bytes
char d; // 1 bytes
};
结构 A
的大小为 16 字节,结构 B
的大小为 24 字节。
通常的解释是,A
的数组应该在数组地址加上索引乘以 A
的大小处访问其元素。
但我不明白为什么会这样。为什么我们不能说 A
的大小为 9 而 B
的大小为 10(均采用 8 字节对齐),并在索引到一个数组时使用特殊的“数组存储”大小数组?
当然,我们仍会以与其对齐方式兼容的方式将这些类型存储在数组中(使用 16 个字节来存储每个 B
元素)。然后,我们将通过考虑它们的对齐来简单地计算元素地址,而不是单独考虑它们的大小(编译器可以静态地这样做)。
例如,我们可以在 B
的 1Kb 字节数组中存储 64 个对象,而不是仅仅 42 个。
最佳答案
在 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
和 union 。
关于c - 为什么结构的大小应反射(reflect)其对齐方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32100031/