本文共 1069 字,大约阅读时间需要 3 分钟。
先来说说为什么要有边界对齐:
简单说,任何CPU都有一个固定的基本长度,下面以32位CPU为例(也有64位或其他的)。CPU在工作时只能按照该长度的整倍数为边界进行内存操作。即只能从地址0、32、64、96...处进行存取,而不能从27、58、83等非边界地址处进行。如果一定要取这些非边界地址处的内容,则必须用若干个操作将其凑出来,因而大大影响存取效率。
另一方面,一个结构体的设计长度却并不一定是32的倍数,例如一个包含六个字符的结构其设计长度仅为48位。如果多个这样的结构在内存中顺着摆放,则许多结构的起始地址将不在边界处。因此,编译程序总是会将每个结构的尾部都加入一些必要的空白,将其凑成32的整数倍。这就是边界对齐的基本道理。
在没有#pragmapack宏的情况下,存在三条原则:
原则1、普通数据成员对齐规则:第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始
比如int在32位机为4字节,则要从4的整数倍地址开始存储
原则2、结构体成员对齐规则:如果一个结构里有某些结构体成员,则该结构体成员要从其内部最大元素大小的整数倍地址开始存储。
如struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储
原则3、结构体大小对齐规则:结构体大小也就是sizeof的结果,必须是其内部成员中最大的对齐参数的整数倍,不足的要补齐
还有一条原则:成员对齐有一个重要的条件,即每个成员按自己的方式对齐。其对齐的规则是,每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里默认是8字节)中较小的一个对齐。并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节
如果有#pragmapack宏,对齐方式按照宏的定义来。比如上面的结构体前加#pragma pack(1),内存的布局就会完全改变。有了#pragma pack(1),内存不会再遵循原则1和原则3了,按1字节对齐。
#pragma pack规定的对齐长度,实际使用的规则是:
结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
也就是说,当#pragmapack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。
而结构整体的对齐,则按照结构体中最大的数据成员和 #pragma pack指定值之间,较小的那个进行。
转载地址:http://yiqai.baihongyu.com/