结构体对齐
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
关于 C 语言中的结构体对齐
(1)什么是字节对齐
一个变量占用 n 个字节,则该变量的起始地址必须能够被n 整除,即: 存放起始地址 % n = 0 ,对于结构体而言,这个 n 取其成员种的数据类型占空间的值最大的那个。
(2)为什么要字节对齐
内存空间是按照字节来划分的,从理论上说对内存空间的访问可以从任何地址开始,但是在实际上不同架构的 CPU 为了提高访问内存的速度,就规定了对于某些类型的数据只能从特定的起始位置开始访问。这样就决定了各种数据类型只能按照相应的规则在内存空间中存放,而不能一个接一个的顺序排列。
举个例子,比如有些平台访问内存地址都从偶数地址开始,对于一个 int 型( 假设 32 位系统 ),如果从偶数地址开始的地方存放,这样一个读周期就可以读出这个 int 数据,但是如果从奇数地址开始的地址存放,就需要两个读周期,并对两次读出的结果的高低字节进行拼凑才能得到这个 int 数据,这样明显降低了读取的效率。
(3)如何进行字节对齐
每个成员按其类型的对齐参数 (通常是这个类型的大小 )和指定对齐参数 ( 不指定则取默认值 ) 中较小的一个对齐,并且结构的长度必须为所用过的所有对齐参数的整数倍 ,不够就补空字节。
这个规则有点苦涩,可以把这个规则分解一下,前半句的意思先获得对齐值后与指定对齐值进行比较 ,其中对齐值获得方式如下:
1. 数据类型的自身对齐值为:对于 char 型数据,其自身对齐值为 1 ,对于 short 型为
2 ,对于 int, long, float 类型,其自身对齐值为 4 ,对于 double 类型其自身对齐值为
8 ,单位为字节。
2. 结构体自身对齐值:其成员中自身对齐值最大的那个值。
其中指定对齐值获得方式如下:
#pragma pack (value) 时的指定对齐值 value 。
未指定则取默认值。
后半句的意思是主要是针对于结构体的长度而言,因为针对数据类型的成员,它仅有一个对齐参数,其本身的长度、于这个对齐参数,即 1 倍。对于结构体而言,它可能使用了多种数据类型,那么这句话翻译成对齐规则:每个成员的起始地址 % 自身对齐值 = 0 ,如果不等于0 则先补空字节直至这个表达式成立。
换句话说,对于结构体而言,结构体在在内存的存放顺序用如下规则即可映射出来:
( 一)每个成员的起始地址 % 每个成员的自身对齐值 = 0 ,如果不等于 0 则先补空字节直至这个表达式成立;
( 二 ) 结构体的长度必须为结构体的自身对齐值的整数倍, 不够就补空字节。
举个例子:
#pragmapack(8)
structA{
chara;
longb;
};
structB{
chara;
structAb;
longc;
};
structC{
chara;
structAb;
doublec;
};
structD{
chara;
structAb;
doublec;
intd;
};
structE{
chara;
intb;
structAc;
doubled;
};
对于 struct A 来说,对于 char 型数据,其自身对齐值为 1,对于 long 类型,其自身对齐值为 4, 结构体的自身对齐值取其成员最大的对齐值,即大小 4 。那么 struct A 在内存中的顺序步骤为:
(1) char a, 地址范围为 0x0000~0x0000, 起始地址为 0x0000, 满足 0x0000 % 1 = 0 ,这个成员字节对齐了。
(2) long b, 地址起始位置不能从 0x00001 开始,因为 0x0001 % 4 != 0, 所 以先补空字节, 直到 0x00003 结束, 即补 3 个字节的空字节, 从 0x00004 开始存放 b, 其地址范围为 0x00004~0x0007.
(二).
b 占四位 )
型,其自身对齐值为 4. 故 struct B 的自身对齐值为 4。那么 structB 步骤为:
(1) char a, 地址范围为 0x0000~0x0000, 起始地址为 0x0000, 满足 0x0000 % 1 = 0 ,这个成员字节对齐了。
(2) struct A b, 地址起始位置不能从 0x00001 开始,因为 0x0001 % 4 != 0, 所以先补空字节,直到 0x00003 结束,即补 3 个字节的空字节,从 0x00004 开始存 放 b, 其地址范围为 0x00004~0x00011.
(3) Io ng c,地址起始位置从 0x000012 开始, 因为 0x0012 % 4 = 0,其地 址范围为 0x00012~0x0015.
(4) 此时成员都存放结束, 结构体长度为 16 ,为结构体自身对齐值的 4 倍,符合条件 (二). 此时满足条件 (一)和条件 (二) , struct B 中各成员在内存中的位置为: a*** b c ,
(3) 此时成员都存放结束,结构体长度为 8 ,为结构体自身对齐值的 2 倍,符合条件
此时满足条件 (一)和条件 (二) , struct A 中各成员在内存中的位置为: a*** b ,si zeof (struct A ) = 8。( 每个星号代表一位, 成员各自代表自己所占的位, 比如 a 占一位,
对于 struct B ,里面有个类型为 struct A 的成员 b 自身对齐值为 4 ,对于 long 类
在内存中的顺序