引言
先看下面这段程序
运行结果(输出)是:
sizeof(C):12
sizeof(D):8
2个结构体,成员个数,成员类型都一样,不同的只是成员的顺序,最终sizeof的结果却不相同。要解释这个问题就需要说明内存对齐。
为什么要对齐
为了能使CPU对变量进行高效快速的访问,变量的起始地址应该具有某些特性,即所谓的"对齐"。
基本概念
数据类型自身的对齐值: 一般地(32位机),对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
结构体或者类的自身对齐值: 其成员中自身对齐值最大的那个值。
指定对齐值: #pragma pack (value)时的指定对齐值value。
数据成员、结构体和类的有效对齐值: 自身对齐值和指定对齐值中小的那个值。
因此,32位机中,#pragma pack(16)是没有意义的(long long的对齐值为8),原因是有效对齐值取自身对齐和指定对齐中小的那个值。
另外,不同的编译器有默认的指定对齐值(这也是为什么同一个结构在不同编译器中sizeof结果不同的原因),如VS系列默认对齐方式为#pragma pack(8),也就是说VS默认以8个字节对齐(如果结构体中某个成员的sizeof大于8)。VC6.0中可以这样修改默认的指定对齐方式:
[Project]|[Settings],c/c++选项卡Category的Code Generation选项的Struct Member Alignment中修改。
显然,编码时,可以通过#pragma动态地修改结构体的指定对齐值。
对齐原则
对齐方式影响结构体成员在结构体中的偏移,不妨设编译器指定对齐参数为n,对于结构体中的某一成员item,它相对于结构首地址的实际字节对齐数目X应该满足以下规则:
X = min ( n, sizeof(item) )
例如,对于结构体 struct A {char a; int b};
当位于32位系统,n=8时:
a的偏移为0,
b的偏移为4,中间填充了3个字节, b的X为4;
当位于32位系统,n=2时:
a的偏移为0,
b的偏移为2,中间填充了1个字节,b的X为2;
再如,对于结构体 struct B{int a;char b;char c;int d};
当位于32位系统,n=8时:
a 的偏移为0,
b的偏移为4,
c的偏移为5,
d的偏移为8,中间填充了2个字节
当位于32位系统,n=2时:
a 的偏移为0,
b的偏移为4,
c的偏移为5,
d的偏移为6
最后,结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。