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

有如下代码段,问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(桩)





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值