一、字节对齐的原因
在访问内存时,如果地址是按4字节对齐,则访问效率会高很多。这种现象的原因在于访问内存的硬件电路。一般情况下,地址总线总是按照对齐后的地址来访问。例如,你想得到0x00000001开始的四字节内容,系统首先需要以0x00000000读四字节,从中取得3字节,然后再用0x00000004作为开始地址,获得下一个4字节,再从中得到第一个字节,再次组合出需要得到的内容。但是,如果地址从一开始就是对齐到0x00000000,则系统只要一次读写即可。
考虑到性能方面,编译器会对结构进行对齐处理。
二、C++字节对齐的规则
在没有使用#pragma pack的情况下,字节对齐大致有以下三条规则:
1.数据成员对齐规则:struct, union的数据成员,第一个数据成员放在offset为0的地方,之后的数据成员的存储起始位置都是放在该数据成员大小的整数倍位置。如在32bit的机器上,int的大小为4,因此int存储的位置都是4的整数倍的位置开始存储。
2.结构体作为数据成员的对齐规则:在一个struct中包含另一个struct,内部struct应该以它的最大数据成员大小的整数倍开始存储。如 struct A 中包含 struct B, struct B 中包含数据成员 char, int, double,则 struct B 应该以sizeof(double)=8的整数倍为起始地址。
3.收尾工作的对齐规则:整个struct的大小,应该为最大数据成员大小的整数倍。
例如:定义如下类:
class MyClass
{
public:
MyClass();
~MyClass();
public:
int a;
char b;
int c;
private:
};
执行如下代码:
MyClass myclass;
printf("0x%08x\n", &myclass.a);
printf("0x%08x\n", &myclass.b);
printf("0x%08x\n", &myclass.c);
输出结果如下:
可以看到myclass类里边变量a和c是int类型,b是char类型,a在内存中开始的地址是4的倍数,虽然b只占用一个字节,但是为了满足c内存地址的开始是4的倍数,b和c之间有三个字节的内存单元没有被占用。
在VC中,使用pack预处理指令来调整字节对齐的规则。
使用#pragma pack(n),指定c编译器按照n个字节对齐;
定义如下类:
class MyClass
{
public:
MyClass();
~MyClass();
public:
<span style="font-family:SimSun;">double</span> d;
float a;
char e;
int b;
char c;
private:
};
执行如下代码:
int _tmain(int argc, _TCHAR* argv[])
{
cout << sizeof(MyClass) << endl;
return 0;
}
在未使用#pragma pack()时,输出结果为:
使用#pragma pack()后,输出结果为: