6

我正在使用 fdump-class-hierarchy 编译器选项,但我不知道如何理解输出。“size”、“align”、“base size”和“base align”是什么意思,如何计算?谢谢!

当代码是:

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
4

1 回答 1

14

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

大小只是它占用的字节数。所以size=16意味着当用作完整类型时,它总是占用 16 个字节。

对齐告诉你对象可以放在哪里:align=8意味着对象的地址必须是 8 的整数倍。

和给出大小base sizebase align对齐方式,以防该类用作基类。它们不同的原因是 C++ 标准允许对象在用作基类时使用较少的填充。

因此,让我们具体看一下您的示例(我假设您实际上在第一种情况下具有int之前的double)。我也省略了publicandprivate因为在这里它们没有改变任何东西(如果你有公共或私有数据成员,他们原则上可以改变一些东西,但我不知道是否有任何编译器利用了这一点)。我也在猜测 and 的大小和对齐方式intdouble实际上我假设的值是很常见的选择,并解释你得到的值)。

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

class A
{
  int m_number;
  double m_nothing;
};

现在int有 size 和 alignment 4,而 double 有 size 和 alignment 8

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

首先,我们有m_number,它占用 4 个字节。我们必须按照给定的顺序排列成员,所以m_number在开头A

iiii

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

iiii****dddddddd

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

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

现在我们找到的对象布局已经满足了这个要求。因此,我们也可以将它原封不动地用于整个对象。因此我们得到size=16align=8为完整的对象。

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

class A
{
  double m_nothing;
  int m_number;
};

现在我们必须从double

dddddddd

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

ddddddddiiii

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

然而,对于作为完整对象的 sue,我们现在发现下一个地址将位于位置 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*******

而那些类型S2看起来像

ddddddddddddddddccc*****

所以底线是具有最高对齐要求的成员应该始终排在第一位。

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

于 2013-07-23T20:25:38.173 回答