简短回答(对于问题的 C++ 部分): The 适用于 C++ 的安腾 ABI https://itanium-cxx-abi.github.io/cxx-abi/abi.html#pod由于历史原因,禁止使用 POD 类型的基础子对象的尾部填充。注意C++11没有这样的禁止。相关规则 3.9/2 允许通过其底层表示复制普通可复制类型,明确排除基本子对象。
长答案:我会尝试同时处理 C++11 和 C。
- 的布局
S1
必须包括填充,因为S1::a
必须对齐int
,和一个数组S1[N]
由连续分配的类型对象组成S1
,其中每个a
成员必须如此对齐。
- 在 C++ 中,可简单复制类型的对象
T
不是基本子对象的可以被视为数组sizeof(T)
字节(即,您可以将对象指针强制转换为unsigned char *
并将结果视为指向 a 的第一个元素的指针unsigned char[sizeof(T)]
,并且该数组的值决定了对象)。由于 C 中的所有对象都是这种类型,这解释了S2
对于 C 和 C++。
- The interesting cases remaining for C++ are:
- 基本子对象,不受上述规则的约束(参见 C++11 3.9/2),以及
- 任何不属于普通可复制类型的对象。
对于 3.1,确实存在常见、流行的“基本布局优化”,其中编译器将类的数据成员“压缩”到基本子对象中。当基类为空时(大小减少了 ∞%!),这是最引人注目的,但适用范围更广。然而,当相应的基本类型是 POD(POD 意味着普通可复制和标准布局)时,我上面链接的用于 C++ 的 Itanium ABI 以及许多编译器实现的 Itanium ABI 禁止此类尾部填充压缩。
对于 3.2,Itanium ABI 的相同部分适用,尽管我目前不相信 C++11 标准实际上强制要求任意的、不可平凡复制的member对象必须与相同类型的完整对象具有相同的大小。
之前的回答留作参考。
我相信这是因为S1
是标准布局,因此出于某种原因S1
- 的子对象S3
保持不变。我不确定标准是否强制这样做。
然而,如果我们转向S1
对于非标准布局,我们观察布局优化:
struct EB { };
struct S1 : EB { // not standard-layout
EB eb;
int a;
char b;
};
struct S3 : S1 {
char c;
};
Now sizeof(S1) == sizeof(S3) == 12
在我的平台上。现场演示 http://ideone.com/g733I0.
这是一个更简单的例子 http://ideone.com/qceEYj:
struct S1 {
private:
int a;
public:
char b;
};
struct S3 : S1 {
char c;
};
混合访问使得S1
非标准布局。 (现在sizeof(S1) == sizeof(S3) == 8
.)
Update:决定性因素似乎是琐碎以及标准布局,即类必须是 POD。以下非 POD 标准布局类是可优化基本布局的:
struct S1 {
~S1(){}
int a;
char b;
};
struct S3 : S1 {
char c;
};
Again sizeof(S1) == sizeof(S3) == 8
. Demo http://ideone.com/xLrj8s