如何理解fdump-class-hierarchy输出

use*_*919 6 c++ class compiler-options

我正在使用fdump-class-hierarchy编译器选项,但我不知道如何理解输出."大小","对齐","基本大小"和"碱基对齐"是什么意思,以及这些是如何计算的?谢谢!

当代码是:

class A
{
public:

private:
    double m_nothing;
    int m_number;
};
Run Code Online (Sandbox Code Playgroud)

输出是:

Class A
   size=16 align=8
   base size=16 base align=8
A (0x406c690) 0
Run Code Online (Sandbox Code Playgroud)

但是,如果我稍微改变一下课程:

class A
{
public:

private:
    int m_number;
    double m_nothing;
};
Run Code Online (Sandbox Code Playgroud)

输出将是:

Class A
   size=16 align=8
   base size=12 base align=8
A (0x406c690) 0
Run Code Online (Sandbox Code Playgroud)

cel*_*chk 14

sizealign为完成型时是尺寸和类的对准.也就是说,如果您创建完整类型是该类型的对象(比如定义该类型的变量,或者使用该类型new).

大小只是它占用的字节数.因此,size=16当用作完整类型时,它总是占用16个字节.

对齐告诉您对象的放置位置:align=8表示对象的地址必须是8的整数倍.

base sizebase align给出的情况下,所述类被用作基类大小和对齐.它们不同的原因是C++标准允许对象在用作基类时使用较少的填充.

因此,让我们专门看一下你的例子(我假设你实际上在第一种情况下有int之前double).我也省略了public,并private因为在这里他们不会改变任何东西(如果你有两个公共或私有数据的成员,他们可能在原则上改变一些东西,但我不知道是否有任何编译器会利用这一点).我也猜的大小和排列intdouble(实际上我假设值是相当普遍的选择,并解释你得到的值).

所以在第一种情况下(我假设)你有

class A
{
  int m_number;
  double m_nothing;
};
Run Code Online (Sandbox Code Playgroud)

现在int有尺寸和对齐4,double有尺寸和对齐8.

所以让我们完成编译器的工作并构建我们的类.

首先,我们有m_number,占用4个字节.我们必须按照给定的顺序放置成员,所以m_number在开始时A:

iiii
Run Code Online (Sandbox Code Playgroud)

到目前为止,我们的大小为4(int的四个字节)和对齐4(因为int具有对齐4).但是现在我们必须添加一个double(大小和对齐8).因为直接在int之后,我们在(相对)地址4,我们没有正确对齐double,所以我们必须添加4个填充字节(我将标记*)以获得8的倍数.因此我们得到我们的课程:

iiii****dddddddd
Run Code Online (Sandbox Code Playgroud)

现在,如果该类被用作基类,我们就完成了.因此我们habe base size=16base align=8(我们需要8的对齐才能正确对齐).

对于完整的对象,还有另一个考虑因素:标准要求在数组中,对象彼此跟随,两者之间没有间隙.也就是说,对象之后的第一个字节必须正确对齐下一个对象.这最终意味着整个对象的大小必须是其对齐的倍数.

现在我们发现的对象布局已经满足了这个要求.因此,对于完整的对象,我们也可以不改变地使用它.因此,我们得到size=16align=8为完整的对象.

现在考虑订单颠倒的情况:

class A
{
  double m_nothing;
  int m_number;
};
Run Code Online (Sandbox Code Playgroud)

现在我们必须从double:

dddddddd
Run Code Online (Sandbox Code Playgroud)

接下来,我们要添加int.事实证明,下一个空闲位置已经正确对齐int,因此我们可以添加它:

ddddddddiiii
Run Code Online (Sandbox Code Playgroud)

现在我们已经准备好了作为基础对象使用.如您所见,我们只需要12个字节base size=12.当然,double为了正确对齐,对象必须再次从8的倍数开始.因此我们有base align=8.

然而,对于作为完整对象的sue,我们现在发现下一个地址将位于第12位,该位置正确对齐该double成员.因此,我们必须添加填充字节,直到我们再次到达正确对齐的地址:

ddddddddiiii****
Run Code Online (Sandbox Code Playgroud)

如您所见,现在我们需要16个字节size=16.我们仍然有align=8两倍.

请注意,对齐要求可能会显着影响类的大小.例如,考虑以下两种类型:

struct S1
{
  char c1;
  double d1;
  char c2;
  double d2;
  char c3;
};

struct S2
{
  double d1;
  double d2;
  char c1;
  char c2;
  char c3;
};
Run Code Online (Sandbox Code Playgroud)

虽然两者都包含相同的成员,S1但是上面的大小和对齐将具有40的总(非基础)大小,而总大小S2将仅为24.实际上,类型的对象S1将作为完整对象看起来像

c*******ddddddddc*******ddddddddc*******
Run Code Online (Sandbox Code Playgroud)

而类型的那些S2看起来像

ddddddddddddddddccc*****
Run Code Online (Sandbox Code Playgroud)

因此,底线是具有最高对齐要求的成员应始终排在第一位.

另请注意,sizeof返回完整对象的大小,即类层次结构转储调用的内容size.