C++结构体字节对齐

结构体为什么要进行字节对齐?主要原因是加快变量在内存的存取速度.我查了相关讨论对齐规则的资料,决定自己整理一下.

本文中基本数据类型占据大小分别为sizeof(char)=1.sizeof(short)=2,sizeof(int)=4,sizeof(float) =4,sizeof(double)=8,测试环境win64+VS2013

对齐主要有两方面,一个是结构体里面的变量字节对齐,一个是结构体本身再进行对齐.

基本对齐

1.变量对齐

结构体中的变量以变量类型在内存中所占据的的字节数为对齐依据,如int占据4个字节,那么int类型变量在结构体中就按照4个字节对齐.

struct stAlign

{

char value1;

int value2;

};

sizeof(stAlign) = 8.

value1是char类型,占据一个字节,value2是int类型,占据4个字节,需要从4的整数倍地址开始分配,于是会从value1后面偏移3个字节的地址开始分配.

2.结构体对齐

struct stAlign3

{

char value1;

int    value2;

char value3;

};

sizeof(stAlign3)=12.

value1占据1个字节,value2先偏移3个字节然后占据4个字节.value3因为char本身就占据1个字节所以不需要偏移,3个变量一共占据9个字节,变量对齐完后,轮到结构体本身进行对齐,先找结构体中占据字节最大的类型,然后让结构体整个占据的大小为该类型的整数倍,stAlign3里面最大的类型为int,占据4个字节,让9匹配到4的整数倍,就是12.同理,如果把int换成double的话,整个结构体占据24个字节.

改变对齐方式

C++中可以通过一些预编译指令来改变结构体的字节对齐方式

1.#pragma pack指令

#pragma pack(push,n)

#pragma pack(pop)

另一对指令同样可以达到改变字节对齐规则的目的

#pragma pack(n)

#pragma pack()

在进行变量对齐时,把变量本身占据的字节和n进行比较,取其中比较小的那个作为对齐依据,如果n大于变量本身占据的字节,则按照自身大小进行对齐,这就是pack的意义,pack即压缩打包,自然是往小的方向对齐。

#pragma pack(push,4)

struct stAlign5

{

char       value1;

short     value2;

double  value3;

};

#pragma pack(pop)

sizeof(stAlign5) = 12

value1占据一个字节,value2是short类型,占据2个字节,把2和4进行对比,取较小的2作为对齐依据,所以偏移量为1,value3是double类型,占据8个字节,把8和4进行对比,取较小的4作为对齐依据,偏移量为0,所以整个占据12个字节.如果没有用pragma指令的话,那么占据的是16个字节.

结构体对齐时,取结构体中占据字节最大的基础类型和n进行对比,取较小的作为对齐依据.

#pragma pack(push,4)

struct stAlign6

{

char      value1;

double  value2;

char      value3;

};

#pragma pack(pop)

按照之前的规则,value1和value2占据12个字节,value3占据1个字节,一共13个字节,这时结构体本身对齐时,结构体中最大的为double,占据8个字节,把8和4对比,取较小的4作为对齐依据,所以占据16个字节,如果没用pragma指令的话, 占据的是24个字节.

对于#pragma pack()指令,简单地说,它指定对齐时两者相比取其小(对于变量而言,拿变量类型占据的大小和n对比,对于结构体而言,拿结构体中最大的基本数据类型占据的大小和n进行比较),大多数情况下,该指令指定结构体往小的方向对齐,目的是为了压缩结构体所占的内存空间.

2._deslspec(align(n))指令

如果使用该指令,那么对于变量来说,对齐的字节大小取变量类型大小与pack(n)与align(n)的最小值,对于结构体来说,对齐的依据是align(n)与结构体中最大成员对齐依据取其大.如果一个成员b是复合结构,以b的对齐依据为准而不是它实际占用的大小.

#pragma pack(push,2)

_deslspec(align(32))

struct stAlign9

{

int value1;

double value2;

char value3;

int value4;

};

#pragma pack(pop)

sizeof(stAlign9) = 32

align(32)与double为8对比取其大,故以32为对齐依据,stAlign9算完成时占据18,最后往32的整数倍对齐,最终占32个字节.

struct st1

{

double value1;

double   value2;

double value3;

};

sizeof(st1) = 24

_deslspec(align(16))

struct st2

{

char value1;

st1   value2;

};

sizeof(st2)=32

最终st2对齐时,取16和value2的对齐8较大的16为依据,所以是32.

3.结构体中含有结构体

如果A结构体中含有B结构体变量,那么最后对A结构体对齐考虑B时,要以B结构体最终的对其依据为参数.

不管一个结构体施加了pragma或者align或者没有,结构体在最终对齐时都有一个对齐依据,指令只是改变了这个对齐依据而已.

#对齐指令

struct B

{

...

};

struct  A

{

 B b;

};

;

假设B最终结构体的对齐为X,那么对于A中的b来说,对齐依据就是X,而不是sizeof(B)

struct B1

{

int value1;

};

sizeof(B1) = 4; //最终对齐依据是4

struct A1

{

char value1;

B1 value2;//以4为对齐依据

};

sizeof(A1) = 8;

_deslspec(align(32))

struct B2

{

int value1;

};

sizeof(B2) = 32; //最终对齐依据是32

struct A2

{

char  value1;

B2 value2;//以32为对齐依据

};

sizeof(A2) = 64;

#pragma pack(2)

struct B3

{

char value1;

int value2;

};

sizeof(B3) = 6; //最终对齐依据为2

#pragam pack()

struct A3

{

char value1;

B3 value3;//以2为对齐依据

};

sizeof(A3) = 8

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值