C++ 如何理解fdump类层次结构输出
我正在使用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
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先出现的结构更大(填充更多)。