字节对齐问题

1.为什么要字节对齐

理论上我们的变量访问在任何地址上都可以,但是事情并没有想的那么简单,体系结构可能会限制我们的行为,它会要求我们对于变量的访问要按一定的规则进行存储和访问。如果我们不是这样来做的话,有些体系结构可能就会出错,例如MIPS,SPARC,也有些不会报错,但是会影响效率,例如X86体系结构。一个简单的例子,有些平台只会从偶地址取数据,所以你如果从奇数地址存储的话,那么可能编译器处理后的指令需要访问2次偶数地址然后再拼接处你需要的地址的数据,这样就会大大的影响效率。

2.平台的对齐规则

默认情况

默认情况下:对于占用N字节的变量访问应该从N字节倍数起始地址开始访问。我们先看一个实例在默认情况下的字节对齐策略;

环境:x86,32bit,gcc

Sizeof(long) = 4;sizeof(short) = 2;sizeof(char) = 1

Struct ex1

{

short a;

Long b;

};

Struct ex2

{

Char c;

Struct ex1 e;

Short d;

};

问:ex2 st2;

sizeof( struct ex1) = ?

Sizeof(struct ex2) = ?

(unsigned int)(&st2.e) - (unsigned int)(&st2) = ?

解答过程:

先看ex1的存储情况,a用了一个字节,b4个字节存储,所以b的起始地址应该是4的倍数,所以a后面填充3个字节,b才开始存储,最后b结束的地址为7,下个地址为8.所以我们的存储空间为8.

如果你以为这样你就分析正确的话,那你可能少做了些什么,如果有这种情况出现的话,你该怎么办,例如struct ex1[4];定义了一个结构体的数组,因为数组的特征规定了数组的元素之间必须紧接着的,同时我们要保证我们的数组的元素要满足对齐规则,最明显的就是例如ex[1]的第一个元素也要满足对齐规则,而第一个元素的起始地址是由前一个结构体元素影响的,如果上面分析正确的话8就是这个ex1的首元素的地址了,它肯定是单字节的倍数了,如果是int放第一个元素,那么8也是4的倍数也成立。所以为了保险期间,我们的结构体最后元素的位置必须是最大字节元素的倍数。这也是第2个条件。而上面的8刚好满足这个条件,所以存储空间为8,即sizeof(struct ex1) = 8

在来看ex2,是个复合结构体,怎么处理呢?起始结构体中的结构体只是为了方便我们书写好看,或则处理方便来做的,其实元素还是按顺序排列在存储空间上的。只不过和结构体数组排列一样,我们要保证子结构体的第一个元素要按要求对齐,保险期间只要我们的子结构的开始地址是我们子结构体最大字节元素的倍数就可以了(既然是最大字节的倍数,那么也肯定是小子节元素的倍数了)。所以存储情况为:1+3(填充)+8+2+2(填充)=16;第二个2字节填充是为了结构体数组而做的,存储空间应该是最大字节元素的倍数(子结构体元素也考虑其中),在这里是子结构体的long4字节。所以sizeof(struct ex2) = 16.

3个答案结构也一看就知道了为4.

上面是用编译器的默认对齐方式,其实对齐方式我们可以修改,使用:

#pragma pack (n)

不过修改规则是:如果n比结构体最大字节元素还大,那么修改不起作用,对齐还是使用最大字节元素对齐方式,即上面的对齐方式。

例如在上面的实例下如果#pragma pack (8)那么最后的结果是一样的。

如果#pragma pack (2),那么分析如下:

先看ex1的存储情况,a用了一个字节,b4个字节存储,本来b的起始地址应该是4的倍数,但是由于是2字节对齐影响,所以a后面填充1个字节,b才开始存储,最后b结束的地址为5,下个地址为6.

6刚好是2的倍数,注意现在可不要求是4的倍数,只要2的倍数就可以了。所以我们的存储空间为6.sizeof (struct ex1) = 6.

同样ex2的子结构第一个元素的对齐方式也受2字节对齐的影响,所以是填充1个字节,最后的存储为置为9,下一个地址为10,同样也是2的倍数,所以存储空间为10。即sizeof(struct ex2) = 10

3个答案就是2了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值