【问题标题】:Memory alignment rules in inheritance继承中的内存对齐规则
【发布时间】:2019-08-17 04:59:07
【问题描述】:

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

  • 该类将具有其最宽成员的对齐方式
  • 类的末尾可以根据其对齐方式进行填充,以防它位于数组中
  • 结构成员根据结构对齐方式对齐

例如:

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 对齐。

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

【问题讨论】:

  • 我不确定这里有什么保证。我认为这是“定义的实现”,但我不太确定。
  • "...每个直接和间接基类都作为基类子对象存在于派生类的对象表示中,位于 implementation-defined 偏移处。 ..." 来源:en.cppreference.com/w/cpp/language/derived_class

标签: c++ alignment


【解决方案1】:

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

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 字节对齐的。也不能保证按照您的 cmets 指示插入填充。这些都是实现定义的。

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

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,而不是依赖内置类型的对齐。

【讨论】:

  • 感谢您的回复。这种传播对于更大的层次结构通常是正确的?我的意思是对齐要求是从最远的基类传播到派生类?
  • 是层次树吗?我的意思是对齐要求由层次结构树分隔?假设 Base1 有它的层次结构树,因此 Base2 和 Base3 分别由树应用 "规则"?
  • @Minee 对于第一条评论,答案(实际上)是肯定的。对于第二条评论,我认为你是对的。 Base1 本身与 Base3 无关,因此它们的对齐要求(实际上)也是单独确定的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多