c – 当扩展一个填充结构时,为什么不能在尾部填充中放置额外的字段?

让我们考虑结构:

struct S1 {
    int a;
    char b;
};

struct S2 {
    struct S1 s;       /* struct needed to make this compile as C without typedef */
    char c;
};

// For the C++ fans
struct S3 : S1 {
    char c;
};

S1的大小为8,这是由于对准而预期的。但是S2和S3的大小是12.这意味着编译器将它们构造为:

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11|
|       a       | b |  padding  | c |  padding  |

编译器可以将c放在6 7 8的填充中,而不会破坏对齐约束。什么是阻止它的规则,什么是背后的原因?

简答案(针对问题的C部分):出于历史原因,Itanium ABI for C++禁止使用POD类型的基本子对象的尾部填充。注意C 11没有这样的禁止。允许通过其底层表示复制可简单复制类型的相关规则3.9 / 2显式地排除了基本子对象。

长答案:我会一次尝试治疗C 11和C.

> S1的布局必须包括填充,因为S1 :: a必须对齐为int,并且数组S1 [N]由类型S1的连续分配的对象组成,其每个成员必须如此对齐。
>在C中,不可以是基本子对象的可简单复制类型T的对象可以被当作sizeof(T)字节的数组(即你可以将一个对象指针转换为一个unsigned char *,并将结果作为指向unsigned char [sizeof(T)]的第一个元素,这个数组的值决定了对象)。因为C中的所有对象都是这种类型,所以这里解释了C和C的S2。
> C剩余的有趣的情况是:

>基本子对象,不受上述规则约束(参见C 11 3.9 / 2)和
>任何非trivially-copyable类型的对象。

对于3.1,确实有常见的,流行的“基本布局优化”,其中编译器将类的数据成员“压缩”到基本子对象中。当基类为空(∞%size reduction!)时,这是最显着的,但是更普遍。然而,上面链接的C的Itanium ABI和许多编译器实现了当相应的基本类型是POD(和POD意味着三可复制和标准布局)时的这种尾部填充压缩。

对于3.2,Itanium ABI的相同部分适用,虽然我目前不相信C 11标准实际上强制任意,非可简单成员对象必须具有与相同类型的完整对象相同的大小。

以前的答案保留作为参考。

我相信这是因为S1是标准布局,所以由于某种原因S3的S1子对象保持不变。我不知道如果这是标准的强制。

然而,如果我们将S1变成非标准布局,我们观察布局优化:

struct EB { };

struct S1 : EB {   // not standard-layout
    EB eb;
    int a;
    char b;
};

struct S3 : S1 {
    char c;
};

现在sizeof(S1)== sizeof(S3)==​​ 12在我的平台上。 Live demo

这里是一个simpler example

struct S1 {
private:
    int a;
public:
    char b;
};

struct S3 : S1 {
    char c;
};

混合访问使S1非标准布局。 (Now sizeof(S1)== sizeof(S3)==​​ 8.)

更新:定义因素似乎是微不足道以及标准布局,即类必须是POD。以下非POD标准布局类是可优化的基本布局:

struct S1 {
    ~S1(){}
    int a;
    char b;
};

struct S3 : S1 {
    char c;
};

再次sizeof(S1)== sizeof(S3)==​​ 8. Demo

http://stackoverflow.com/questions/24110347/when-extending-a-padded-struct-why-cant-extra-fields-be-placed-in-the-tail-pad

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:c – 当扩展一个填充结构时,为什么不能在尾部填充中放置额外的字段?