结构是如何对齐的?

  对于结构体,编译器会自动进行成员变量的对齐,以提高运算效率。结构对齐为什么能提高效率呢?原因在于,为了访问未对齐的内存,处理器需要作两次内存访问,而对齐的内存访问仅需要一次访问。编译器为结构体的每一个成员按照按其自然对界(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。)条件进行分配空间。

默认情况下,结构采用自然对界(natural alignment)的对齐方式,即按结构体的成员中size最大的成员对齐。举例如下:

struct aligntExample
{
    char a;
    short b;
    char c;
};
在上述结构体中,size最大的是short,其长度为2字节,因而结构体中的char成员a、c都以2为单位对齐,sizeof(aligntExample)的结果等于6。

默认的对齐方式可以通过#pragma  pack(n)来自定义对齐方式,其中"n"表示采用多少个字节进行对齐。

 

win32中约定的对齐方式为如下所示:
数据类型     对齐方式      
char    按一字节的倍数对齐      
short    按二字节的倍数对齐      
int/long    按四字节的倍数对齐      
float    按四字节的倍数对齐      
double    按八字节的倍数对齐      
结构体    按结构中成员最大的对齐方式对齐     

前面四种数据类型的对齐是指该成员一定要放在自身长度的整数倍数的地址上,而结构体的对齐是指结构的总大小一定要是结构的倍数。

所以,结构的对齐问题包含了2个方面:一是结构成员的对齐,一是整个结构体大小的对齐。

#pargma pack(n)施加于结构上以后,我们该怎么计算结构的大小呢?

计算方法如下:
   结构的数据成员第一个一定放在偏移为0的地方,后续每个数据成员的对齐,按照这个数据成员自身长度和要求的对齐长度n中比较小的那个进行计算,而最后整个结构的对齐,则按照结构中成员基本类型长度最大的和要求的对其长度n中比较小的那个进行比较计算。举例如下:
#pargma pack(4)
typedef struct alignment
{
    long A1;
    char B2;
    short C3;
    char D4;
    long E5;
    long F6;
    char G7;
}ALIGNMENT;
#pargma pack()

1)第一个成员A1为long,自身长度为4,放在偏移为0的地址,占用4个字节,地址空间为0~3,下一个地址为4;
2)第二个成员B2为char,自身长度为1,必须放在min(1,n) = 1的倍数地址上,当前地址为4,符合,所以放在偏移为4的地址上,占用一个字节,地址空间为4,下一地址为5;
3)第三个成员C3为short,自身长度为2,必须放在min(2,n) = 2的倍数地址上,当前地址为5,不符合,所以C3向后移动放在偏移为6的地址上,地址5空出,占用两个字节,地址空间为6~7,下一地址为8;
4)第四个成员D4为char,自身长度为1,必须放在min(1,n) = 1的倍数地址上,当前地址为8,符合,所以D4放在偏移为9的地址上,占用一个字节,地址空间为8,下一地址为9;
5)第五个成员E5为long,自身长度为4,必须放在min(4,n) = 4的倍数地址上,当前地址为9,不符合,所以E5放在偏移为12的地址上,占用4个字节,地址空间为12~15(9~11空出),下一地址为16;
6)第六个成员F6为long,自身长度为4,必须放在min(4,n) = 4的倍数地址上,当前地址为16,符合,所以F6放在偏移为16的地址上,占用4个字节,地址空间为16~19,下一地址为20;
7)第七个成员G7为char,自身长度为1,必须放在min(1,n) = 1的倍数地址上,当前地址为20,符合,所以G7放在偏移为20的地址上,占用1个字节,地址空间为20,下一地址为21;

最后,整个结构的对齐(即结构的大小),必须是min(结构中成员基本类型长度最大的,n) = 4的倍数,现在结构占用了0~20的空间,占用21个字节,所以补3个字节,占用21~23,总共24个字节,结构之后的变量占用的地址从24开始,保证后续变量在整数边界处。

最终结果:sizeof(ALIGNMENT) = 24。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值