是否采用C ++标准来对齐这样的结构

时间:2012-11-08 14:02:04

标签: c++ x86

以此为例

class A
{
public:
  int a; 
  char b;
  int c;
};

我看到每个编译器(对于x86,32或64位)为类A分配12个字节,而不是9.所以他们将b对齐到整数边界或总线边界,你可以说。我的问题是,如果这是在C ++标准中这样做,并且是否有任何编译器不这样做。

5 个答案:

答案 0 :(得分:15)

C ++标准规定:

  • 对象具有对齐要求,其大小为多个(因此,如果int为4字节宽,则需要对齐1,2或4个字节,具体取决于实现方式。)
  • 成员对象(如果它们没有被访问说明符分隔,例如public)都按照它们被声明的顺序分配
  • 并根据他们的对齐要求分配他们。

所以不,标准并没有确切地说该类的大小应该是12个字节。

确实表示b应在a之后分配,而c应在b之后分配。

int为4字节宽且需要4字节对齐的平台上,这会留下12个字节作为最小有效大小:

  • a占用前4个字节
  • b需要一个字节
  • c需要4个字节,但必须在4字节边界上分配b结束了一个字节过去这样的边界,因此通过插入3个字节的填充来找到放置c的下一个有效位置。

所以类的总大小最终是成员的大小(4 + 1 + 4 = 9)加上三个字节的填充,总共12个。

还有另一条规则在这里没有效果,但如果您按照a, c, b的顺序定义了成员,则会很重要。

包含类(A)继承了严格对齐的成员对象的对齐要求。也就是说,因为它包含int,所以它具有与int相同的对齐要求。并且因为对象的总大小必须是其对齐要求的倍数,所以包含a, b, c顺序的成员的类仍然需要12个字节的存储空间。它只是将3个字节的填充转移到类的末尾,而不是bc之间。

但是,在其他一些情况下,按大小降序重新排序成员可以有时减少类的大小。

假设我们有一个这样的类:

class B {
  char a;
  double b;
  int c;
};

这将需要24个字节的存储空间(a为1个字节,b为8个字节,c为4个字节,但确保b结束在8字节边界上,我们在ab之间需要 7 字节的填充,并确保整个类最终的大小为8的倍数,我们需要c后的另外4个字节。

但是按照大小重新排序成员,如下:

class B {
  double b;
  int c;
  char a;
};

导致一个类只需要16个字节:

成员对象本身的1 + 4 + 8字节相同,但现在c已经在4字节边界上对齐(因为它位于b之后,以8字节结束({1}}永远不需要任何对齐,所以我们需要的唯一对齐是确​​保a的大小是8的倍数。成员占用13个字节,所以我们可以添加3个填充字节,类最终为16字节,比第一个版本小33%。

答案 1 :(得分:1)

可以使用编译指示指令在编译时控制结构打包。 的 See #Pragma Pack

例如,以下内容未对齐成员,并将它们放在彼此旁边。

#pragma pack(push, 1)
struct A4
{
  char a;
  double b;
  char c;
};
#pragma pack(pop)

来自 here 的示例。

GCC 也支持pragma pack。该指令不是某些标准的一部分,但很多编译器都支持它。


但是,没有理由这样做。编译器将它们对齐以加快对成员的访问,并且没有理由改变

答案 2 :(得分:0)

Standard允许编译器在必要时填充更多字节。它主要取决于主机的架构而不是编译器。

答案 3 :(得分:0)

是的,标准中到处都提到了对齐,主要是3.11节( Alignment )。它取决于平台,因此任何依赖于对象实际大小的程序本质上都是不可移植的。

答案 4 :(得分:0)

在您的情况下,'b'始终正确对齐。 填充以在32位边界中对齐 c 。即使有特定实现的空间,大多数编译器都遵循将2字节和4字节变量与2字节和4字节边界对齐的规则。

在32位系统中,双精度和长整数(8字节)与4字节边界对齐,但在64位系统中与8字节对齐。