对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。显然在读取效率上下降很多。
1 自然对界
各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。自然对界(natural alignment)即默认对齐方式,是指按结构体的成员中size 最大的成员对齐。
例如:
struct naturalalign
{
char a;
short b;
char c;
};
在上述结构体中,size 最大的是short,其长度为2 字节,因而结构体中的char 成员a、c 都以2 为单位对齐,
sizeof(naturalalign)的结果等于6;
如果改为:
struct naturalalign
{
char a;
int b;
char c;
};
其结果显然为12。
2 指定对界
一般地,可以通过下面的方法来改变缺省的对界条件:
· 使用伪指令#pragma pack (n),编译器将按照n 个字节对齐;
· 使用伪指令#pragma pack (),取消自定义字节对齐方式。
注意:如果#pragma pack (n)中指定的n 大于结构体中最大成员的size,则其不起作用,结构体
仍然按照size 最大的成员进行对界。
例如:
#pragma pack (n)
struct naturalalign
{
char a;
int b;
char c;
};
#pragma pack ()
当n 为4、8、16 时,其对齐方式均一样,sizeof(naturalalign)的结果都等于12。而当n 为2
时,其发挥了作用,使得sizeof(naturalalign)的结果为6。
3 实际对齐方式:
Actual Align = min ( Order Align, Natual Align )
对于复杂数据类型(比如结构等):实际对齐方式是其成员最大的实际对齐方式:
Actual Align = max( Actual align1,2,3,…)
4 几个例子:
struct A
{
int a;
char b;
short c;
}; //size = 8
struct B
{
char b;
int a;
short c;
};//size = 12
#pragma pack (2) /*指定按2字节对齐*/
struct C
{
char b;
int a;
short c;
}; //size = 8
#pragma pack () /*取消指定对齐,恢复缺省对齐*/
#pragma pack(8)
struct example1
{
short a;
long b;
};//size = 8 指定对齐大于自然对齐,无效
struct example2
{
char c;
example1 struct1;
short e;
}; //size = 16 实际对齐方式按最大成员(example1)为4
#pragma pack()
#pragma pack(8) //指定Align为 8
struct STest1
{
char ch1;
long lo1;
char ch2;
} // size = 12 指定对齐大于自然对齐,无效
#pragma pack()
struct STest2
{
char ch3;
STest1 test;
}// size = 16 按STest1对齐
#pragma pack(2) //指定Align为 2
struct STest3
{
char ch3;
STest1 test;
}// size = 14
#pragma pack()
5 注意事项:
1、 这样一来,编译器无法为特定平台做优化 ,如果效率非常重要,就尽量不要使用#pragma pack, 尽量用好的定义来压缩空间,把结构中的变量按照 类型从小到大声明,尽量减少中间的填补空间 。 如果必须使用,也最好仅在需要的地方进行设置。
2、需要加 pack 的地方一定要在定义结构的头文件中加,不要依赖命令行选项,因为如果很多人使用该头文件,并不是每个人都知道应该 pack 。 这特别表现在为别人开发库文件时,如果一个库函数使用了struct作为其参数,当调用者与库文件开发者使用不同的 pack 时,就会造成错误,而且该类错误很不好查。
3、 在VC及BC提供的头文件中,除了能正好对齐在四字节上的结构外,都加了 pack ,否则 我们编的Windows程序哪一个也不会正常运行。
4、 在 # pragma pack (n) 后一定不要include其他头文 件,若包含的头文件中改变了align值,将产生非预期结果。
5、 不要多人同时定义一个数据结构。这样可以保证一致的 pack 值。