以此为例
class A
{
public:
int a;
char b;
int c;
};
我看到每个编译器(对于x86,32或64位)为类A
分配12个字节,而不是9.所以他们将b
对齐到整数边界或总线边界,你可以说。我的问题是,如果这是在C ++标准中这样做,并且是否有任何编译器不这样做。
答案 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个字节的填充转移到类的末尾,而不是b
和c
之间。
但是,在其他一些情况下,按大小降序重新排序成员可以有时减少类的大小。
假设我们有一个这样的类:
class B {
char a;
double b;
int c;
};
这将需要24个字节的存储空间(a
为1个字节,b
为8个字节,c
为4个字节,但确保b
结束在8字节边界上,我们在a
和b
之间需要 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字节对齐。