C++ 如何理解fdump类层次结构输出

C++ 如何理解fdump类层次结构输出,c++,class,compiler-options,C++,Class,Compiler Options,我正在使用fdump类层次结构编译器选项,但我不知道如何理解输出。“大小”、“对齐”、“基本大小”和“基本对齐”是什么意思,以及如何计算它们?谢谢 当代码为: class A { public: private: double m_nothing; int m_number; }; 输出为: Class A size=16 align=8 base size=16 base align=8 A (0x406c690) 0 但是,如果我稍微改变一下课程: clas

我正在使用fdump类层次结构编译器选项,但我不知道如何理解输出。“大小”、“对齐”、“基本大小”和“基本对齐”是什么意思,以及如何计算它们?谢谢

当代码为:

class A
{
public:

private:
    double m_nothing;
    int m_number;
};
输出为:

Class A
   size=16 align=8
   base size=16 base align=8
A (0x406c690) 0
但是,如果我稍微改变一下课程:

class A
{
public:

private:
    int m_number;
    double m_nothing;
};
输出将是:

Class A
   size=16 align=8
   base size=12 base align=8
A (0x406c690) 0

size
align
是类用作完整类型时的大小和对齐方式。也就是说,如果您创建的对象的完整类型是该类型(比如定义该类型的变量,或者将该类型与
new
一起使用)

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

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

base size
base align
给出了类用作基类时的大小和对齐方式。它们不同的原因是C++标准允许对象在使用基类时使用较少的填充。 让我们具体来看一下您的示例(我假设在第一种情况下,在
double
之前有
int
)。我还省略了
public
private
,因为在这里它们不会改变任何东西(如果您同时拥有public或private数据成员,原则上它们可以改变一些东西,但我不知道是否有编译器利用了这一点)。我还猜测了
int
double
的大小和对齐方式(实际上我假设的值是非常常见的选择,并解释了您得到的值)

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

现在
int
有大小和对齐
4
,double有大小和对齐
8

因此,让我们完成编译器的工作并构建我们的类

首先,我们有
m_number
,它占用4个字节。我们必须按照给定的顺序排列成员,因此
m_number
位于
A
的开头:

iiii
到目前为止,我们有大小4(int的四个字节)和对齐方式4(因为int有对齐方式4)。但现在我们必须添加一个双精度(大小和对齐8)。因为直接在int之后,我们位于(相对)地址4,我们没有正确对齐double,所以我们必须添加4个填充字节(我将用
*
标记),以获得8的倍数。因此,我们为我们的班级得到:

iiii****dddddddd
现在,如果将该类用作基类,我们就完成了。因此,我们有
base size=16
base align=8
(我们需要对齐8才能正确对齐双精度)

对于完整的对象,还有另一个需要考虑的问题:标准要求在数组中,对象相互跟随,中间没有间隙。也就是说,对象后的第一个字节必须与下一个对象正确对齐。这最终意味着整个对象的大小必须是其对齐的倍数

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

现在考虑顺序颠倒的情况:

class A
{
  double m_nothing;
  int m_number;
};
现在我们必须从双倍的
开始:

dddddddd
接下来,我们必须添加
int
。事实证明,下一个空闲位置已经正确对齐了
int
,因此我们只需附加它:

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

但是对于sue as complete对象,我们现在发现下一个地址将位于位置12,对于
double
成员,该位置没有正确对齐。因此,我们必须添加填充字节,直到再次达到正确对齐的地址:

ddddddddiiii****
如您所见,现在我们需要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;
};
虽然两者都包含相同的成员,
S1
的总大小(非基准)为40,而
S2
的总大小仅为24。实际上,
S1
类型的对象作为完整对象,看起来像

c*******ddddddddc*******ddddddddc*******
ddddddddddddddddccc*****
S2
类型的

c*******ddddddddc*******ddddddddc*******
ddddddddddddddddccc*****
因此,底线是具有最高对齐要求的构件应始终排在第一位


还要注意,
sizeof
返回完整对象的大小,也就是类层次结构转储调用的
size

我认为您忘记了实际更改一点类。哦,对不起!在第二个例子中,我交换了两个成员的变量。答案很好。在我看来,如果一个人总是先声明最大的成员,他就会得到更小的类。我说的对吗?这不是尺寸,而是与此相关的对齐方式。例如,
struct X{char s[17];}
大于
double
,但对齐方式为1(且大小不是double对齐方式的倍数)。一个包含
X
double
以及
char
的结构比double先出现的结构更大(填充更多)。