您的位置:首页 > 编程语言 > C语言/C++

编译器对齐机制——由一道求C++类大小的题说开

2016-01-19 18:43 405 查看
有如下代码段,问32位下sizeof(a)是多少

class A
{
int i;
union U
{
char buff[13];
int i;
}u;
void foo(){}
typedef char* (*f)(void*);
enum{red,green,blue}color;

}a;
结果是24,原因,int i占4字节,union U u占16字节,枚举值color占4字节。

难点集中在union的大小,取最大应该是13,而不是16。

16是怎么来的,是对齐机制,巧就巧在这个对齐上,如果如题中所示,那么它的大小是16

union U
{
char buff[13];
int i;
}u;


如果没有那个int,又会是多少?

union U
{
char buff[13];
}u;
其实这时候就是13了,可以看到这个对齐是遇到int才出现的。

但是,其实这个结果是可变的,上边的都是gcc/g++自动出的结果,其实是可以手动改的。用#pragma pack(1)改对齐为1,结果就

#pragma pack(1)
class A
{
int i;
union U
{
char buff[13];
int i;
}u;

void foo(){}
typedef char* (*f)(void*);
enum{red,green,blue}color;

}a;

这样一来,结果就不是24了,而是21。

结论就是,同一个联合体(结构体其实也一样)内,char本来是1对齐,碰到int就变成了4对齐,经测试(32位,g++/gcc),double也是4对齐,short是2对齐,反正都是要随那个宽的变。这个“碰到”在一个结构体或联合体内是不分先后的,先int还是后int,最后sizeof()结果都一样。

但是#pragma pack是分先后的,即时生效,什么时候设置,在那后边就全是设置的值。如下

class A
{
int i;
union U
{
char buff[13];
int i;
}u;
#pragma pack(1)
char buff[13];
void foo(){}
typedef char* (*f)(void*);
enum{red,green,blue}color;

}a;
sizeof(a)结果是37,后边这个buff[13]是1对齐,前边那个buff[13]依然是4对齐!!!

所以说,那个题不严谨,他只展现了一部分,而不是整个带main的程序,如果真的放在一个大工程下,如果事先有主动设置的对齐值,结果就不一样了(pack参数也可以是2或者4)。

最后,自定义完了别忘了#pragma pack()恢复默认值,以免影响后边的类定义。

PS:编译器的个性化的东西很多,不属于语言本身,比如,同样是空结构体和联合体,用g++看zieof()结果就是1,而gcc看就是0,有的编译器可能干脆不让你编译通过,以提醒你那是空的,不过空的也有空的用处,内存占位——stub(桩)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  sizeof class