字节对齐的作用
-
节约内存空间,对于一个结构体 不同的成员变量顺序会影响最终存储占用的空间
-
加深对不同平台字节数的理解和记忆
什么是字节对齐
-
一般是相对于结构体而言
-
说人话就是,结构体最终占用的空间,往往不是看起来占用的空间
-
总结起来就是按照结构体的顺序挨个存,存之前必须确保当前大小是接下来要存的变量大小整数倍,最后存完要确保是结构体最大的变量大小的整数倍
-
可能有点抽象,主要涉及几个概念:当前大小 接下来要存的变量大小 结构体最大的变量大小
举例讲解
struct A{
uint_8 a;
uint_16 b;
uint_32 c;
uint_64 d;
}
先明确一点,系统要求的大小,学名叫系统默认对齐字节数,我目前遇到的任务,要求是4字节,因地制宜
- 按照顺序存储,先存a,当前大小就是0,接下来要存的变量(a)大小就是1字节(uint_8表示跨平台8位)
- 存b,依次是 当前大小1字节,接下来要存的b是2字节,由于:
确保当前大小是接下来要存的变量大小整数倍
1不是2的整数倍,所以要补充一字节到2! - 存c,当前大小2+2=4字节,接下来要存的c是4字节。所以直接存就行
- 存d,当前大小4+4=8字节,接下来要存的d,看似8字节,实则系统要求最多4字节,所以只能分开存!!!!
- 结构体最大的变量大小,也就是max(1,2,4,8)得8,16是他的整数倍,所以最后不用扩
所以:接下来要存的字节数 = min(系统要求的字节数,该变量占用的字节数)
综上所述,结构体成员变量字面上占用1+2+4+8=15字节,实际占用1+1+2+4+4+4 = 16字节!!!
其他要注意的
- 数组一个一个存,实际上只要数组第一个元素对齐了后面自动对齐,因为第一个前面的是n倍了,继续加同类型变量就是n+1倍
- 不同的顺序会导致不同的结果,比如上面这个例子,按照uint_8 uint_32 uint_16 uint_64存,存uint_32就需要对齐3个,一共需要1+3+4+2+4+4=18字节,最后在对齐整体做到4的倍数(为什么不是8呢,因为被截断了)也就是需要20字节!!
- 数组比如int[5],不会改变“结构体最大的变量大小”,因为是每个元素依次存储的!
- 全uint_8或者char(绝大多数平台都是1字节)是最好的,因为不需要任何字节对齐!
改变系统默认字节对齐数
pragma pack()命令可以指定默认对齐字节数,可选参数有1/2/4/8/16,不带参或参数非以上值时,将恢复默认值。
#pragma pack(2)
struct xxx{
}
#pragma pack()
判别步骤
注意的点
- 先看系统默认对齐字节数是多少,如果很大比如16,那么“接下来要存的变量大小”就是该变量实际大小,存前考虑前面的值对齐
- 如果系统默认字节数是1 2 这种比较小的,那么“接下来要存的变量大小”很可能要被截断!!!
步骤
- 按结构体内变量的顺序找,从第一个开始存,min(名义占字节,系统默认对齐字节)得到的值就是存这个变量实际小号的内存空间
- 依次寻找最后相加
- 记录最长的内存段,这个值=最大的内存片段,如果系统默认很小会被截断,比如系统默认是1,那么就是1没得商量,每个片段都是1,,最后要补到1的倍数也就是不用补