首页 > 解决方案 > 继承中的内存对齐规则

问题描述

我试图弄清楚在继承的情况下类对齐是如何工作的。目前我明白

例如:

struct Nested { // Due to the long long element it is 8 aligned
    short int ShortNestedElement; //6 bytes of padding here        
    long long int LongNestedElement;
};

struct Example {
    short int ExampleMember_1; // 6 bytes of padding here
    Nested ExampleMember_2;
    char ExampleMember_2; // 7 bytes of padding here  
};

我的困惑来自于继承:

struct Base1 {
    short unsigned int Base_1Member_1;
    long unsigned int Base_1Member_2;
};

struct Base2 {
    unsigned int Base_2Member_1;
};


struct Base4 {
    unsigned int Base_4Member_1;
};

struct Base3 : Base4 {
    long unsigned int Base_3Member_1;
};

struct Final: Base1, Base2, Base3 {
};

根据 clang 类 Final 的布局是:

*** Dumping AST Record Layout
         0 | struct Final
         0 |   struct Base1 (base)
         0 |     unsigned short Base_1Member_1
         8 |     unsigned long Base_1Member_2
        16 |   struct Base2 (base)
        16 |     unsigned int Base_2Member_1
        24 |   struct Base3 (base)         --------> ? 
        24 |     struct Base4 (base)
        24 |       unsigned int Base_4Member_1
        32 |     unsigned long Base_3Member_1
           | [sizeof=40, dsize=40, align=8,
           |  nvsize=40, nvalign=8]

我不明白为什么,当我们考虑 Base3 时,即使它继承自 Base4(因此 Base4 的成员位于 Base3 之前),我们会考虑 Base3(8) 而不是 Base4(4) 的对齐方式。但是,如果我更改这两个类的内容,使 Base3 与 4 对齐,Base4 与 8 对齐,则需要 Base4 对齐。

它是继承层次结构中最广泛的类吗?

标签: c++alignment

解决方案


这在很大程度上取决于实现。在您的代码中:

struct Nested { // Due to the long long element it is 8 aligned
    short int ShortNestedElement; //6 bytes of padding here        
    long long int LongNestedElement;
};

struct Example {
    short int ExampleMember_1; // 6 bytes of padding here
    Nested ExampleMember_2;
    char ExampleMember_2; // 7 bytes of padding here  
};

long long不必是 8 个字节,short不必是 2 个字节,char也不必是 1 个字节。如果是,则long long不必是 8 字节对齐的,short不必是 2 字节对齐的,char也不必是 1 字节对齐的。也不保证按照您的评论指示插入填充。这些都是实现定义的

现在让我们看看你的问题:

struct Base1 {
    short unsigned int Base_1Member_1;
    long unsigned int Base_1Member_2;
};

struct Base2 {
    unsigned int Base_2Member_1;
};


struct Base4 {
    unsigned int Base_4Member_1;
};

struct Base3 : Base4 {
    long unsigned int Base_3Member_1;
};

struct Final: Base1, Base2, Base3 {
};

我不明白为什么,当我们考虑 Base3 时,即使它继承自 Base4(因此 Base4 的成员在 Base3 之前),我们会考虑 Base3(8) 而不是 Base4(4) 的对齐方式。但是,如果我更改这两个类的内容,使 Base3 与 4 对齐,Base4 与 8 对齐,则需要 Base4 对齐。

如果Base3继承自Base4,则Base4是 的子对象Base3,因此 的对齐要求Base4有效地传播到Base3。因此,alignof(Base3)成为其成员的较大的alignof(Base4)和对齐的要求。因此,实际上,它占据了“层次结构中最广泛的”。至少,现实世界的对齐方式就是这样。

同样,该标准没有指定这类事情。不能保证alignof(Base3) == std::max(alignof(Base4), alignof(unsigned long))


以后在讨论对齐的时候,请使用alignas而不是依赖内置类型的对齐。


推荐阅读