内存字节对齐
对齐的三个原则
如何内存对齐?sizeof的结果怎么来的?请记住以下3条原则:(在没有#pragma pack宏的情况下)
原则1:结构(struct)或联合(union)的数据成员,存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如:假设一个数据成员为int,int在32位机上为4字节,则要从4的整数倍地址开始存储)
原则2:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(比如:struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储)
原则3:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
内存字节对齐的原因
根本原因在于CPU访问数据的效率问题。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。
举例1
typedef struct bb
{
int id; //0~3
double weight; //8~15 原则1
float height; //16~19 要为8的整数倍,补齐20~23 原则3
}BB;
typedef struct aa
{
char name[2]; //0~1 申请了两个char空间,所以是占用2个字节
int id; //4~7 原则1
double score; //8~15
short grade; //16~17
BB b; //24~47 要从8的整数倍开始存 原则2
}AA;
int main()
{
AA a;
cout<<sizeof(a)<<" "<<sizeof(BB)<<endl;
return 0;
}
结果是48 24
举例2
在32位cpu上选择缺省对齐的情况下,有如下结构体定义:
struct A
{
unsigned a : 19;//后面的数字表示bit
unsigned b : 11;
unsigned c : 4;
unsigned d : 29;
char index;//1个字节=8bit
};
struct A
{
unsigned a : 19;//后面的数字表示bit
unsigned b : 11;
unsigned c : 4;
unsigned d : 29;
char index;//1个字节=8bit
};
则sizeof(struct A)的值为?
解答:由32位缺省对齐,所以有:
由于19+11=30<32,19和11算作32位,即4个字节
由于4+29>32,4算作32位,即4个字节
由于29+8>32,29算作32位,即4个字节
由于8<32,8算作32位,即4个字节
所以,总共有16个字节!sizeof(struct A)的值为16。
用pragma控制内存对齐
再讲讲#pragma pack():在代码前加一句#pragma pack(1),你会发现上面的代码输出为32 16,因为bb是4+8+4=16,aa是2+4+8+2+16=32。这不就是理想中的没有内存对齐的世界嘛。
下面的代码,在#pragma pack(4)和#pragma pack(8)的情况下,结构体的大小分别是:
struct One{
double d;
char c;
int i;
}
struct Two{
char c;
double d;
int i;
}
所以,答案为16,16,16,24