一、什么是对齐
现在使用的计算机中内存空间都是按照字节划分的,从理论上讲似乎对任何类型的变量的访问都可以从任何地址开始,但实际上计算机系统对于基本数据类型在内存中的存放位置都有限制。举个例子,一个变量占用n个字节,则该变量的起始地址必须能够被n整除,即存放起始地址%n = 0。各种基本数据结构类型在内存中是按照这种规则排列,而不是一个紧接着一个排列的。这就是内存对齐。
对结构体而言,存储的起始地址必须能被其成员中的数据类型占空间的值最大的那个整除。
二、对齐的作用和原因
内存对齐作为一种强制的要求,第一简化了处理器与内存之间传输系统的设计,第二可以提升读取数据的速度。 各个硬件平台对存储空间的处理有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。
三、对齐的原则
在不使用#pragma pack宏的情况下,结构体的对齐原则有如下几个:
原则一、数据成员按数据类型自身的对齐值对齐:结构的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始。
原则二、结构体中有某些结构体成员,则结构体成员要按自身结构体内部最大对齐值进行对齐。一个简单的例子:struct A中包含struct B类型的成员,B中有char、int、double元素,那么B应该从sizeof(double)的整数倍开始存储。
原则三、结构体的自身对齐值是其成员中自身对齐值最大的那个值。即结构体的总大小,必须是其内部最大成员的整数倍,不足的要补齐。
下面通过几个例子,加深对这几个原则的理解:(32位系统,gcc编译器)
struct A{
int a1;
int a2;
};
struct B{
char b1;
int b2;
};
struct C{
short c1;
char c2;
long c3;
};
struct D{
short d1;
long d2;
char d3;
};
struct E{
char e1;
struct C e2;
short e3;
};