The size
and align
是用作完整类型时类的大小和对齐方式。也就是说,如果您创建的对象的完整类型是该类型(例如定义该类型的变量,或者将该类型与new
).
大小只是它占用的字节数。所以size=16
表示当用作完整类型时,它始终占用 16 个字节。
对齐方式告诉您可以放置对象的位置:align=8
表示对象的地址必须是8的整数倍。
The base size
and base align
给出该类用作基类时的大小和对齐方式。它们不同的原因是 C++ 标准允许对象在用作基类时使用更少的填充。
所以让我们具体看看你的例子(我假设你实际上有int
之前double
在第一种情况下)。我也省略了public
and private
因为在这里他们不会改变任何东西(如果你有公共或私人数据成员,他们could原则上改变一些东西,但我不知道是否有任何编译器利用了这一点)。我也在猜测的大小和对齐方式int
and double
(实际上我假设的值是非常常见的选择,并解释你得到的值)。
所以在第一种情况下(我假设)你有
class A
{
int m_number;
double m_nothing;
};
Now int
有大小和对齐方式4
,并且 double 具有大小和对齐方式8
.
因此,让我们完成编译器的工作并构建我们的类。
首先,我们有m_number
,占用4个字节。我们必须按照给定的顺序放置成员,所以m_number
开始于A
:
iiii
到目前为止,我们的大小为 4(int 的四个字节),对齐方式为 4(因为 int 的对齐方式为 4)。但现在我们必须添加一个双精度(大小和对齐方式 8)。由于直接在 int 之后,我们位于(相对)地址 4,因此我们没有正确对齐 double,因此我们必须添加 4padding字节(我将用它标记*
) 得到 8 的倍数。因此我们的类得到:
iiii****dddddddd
现在,如果将该类用作基类,我们就完成了。因此我们有base size=16
and base align=8
(我们需要对齐 8 才能正确对齐双精度)。
对于完整的对象,还有另一个考虑因素:标准要求在数组中,对象彼此跟随,中间没有间隙。也就是说,该对象之后的第一个字节必须与下一个对象正确对齐。这最终意味着完整对象的大小必须是其对齐方式的倍数。
现在我们发现的对象布局已经满足了这个要求。因此,我们也可以将其用于完整的对象,无需更改。因此我们得到size=16
and align=8
对于完整的对象。
现在考虑顺序颠倒的情况:
class A
{
double m_nothing;
int m_number;
};
现在我们必须从double
:
dddddddd
接下来,我们必须添加int
。事实证明,下一个空闲位置已经正确对齐int
,因此我们可以附加它:
ddddddddiiii
现在我们已准备好用作基础对象。正如你所看到的,我们只需要 12 个字节,因此base size=12
。当然对于double
为了正确对齐,对象必须再次从 8 的倍数的地址开始。因此我们有base align=8
.
然而,对于作为完整对象的 sue,我们现在发现下一个地址将位于位置 12,即not正确对齐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
.