什么是字节对齐?
计算机并非逐字节读取内存,而是按2,4,8的倍数的字节块读写内存,故地址必须为上述倍数,故各种数据类型需要按照一定规则在空间上排列
对齐准则
- 结构体变量首地址可被对齐字节数大小所整除
- 结构体每个成员相对该结构体首地址的偏移都是成员大小的整数倍(如需要,填充字节)
- 结构体总大小为结构体对齐字节数大小的整数倍
为什么要字节对齐?
可优化【读写效率】【空间存储】【跨平台通信】
读写效率
考虑场景如下:若计算机每次读取8字节块,此时读取一个double,若未字节对其,可能该double位与两个不同的字节块,需要做两次读取才能读出double的值,显然效率低下!
空间存储
字节对齐的细节由编译器实现,为何我们还需要考虑字节对齐?
考虑如下代码
#include<stdio.h>#include<stdint.h>#ifdef DEBUGstruct test{int a;char b;int c;short d;test(int v1, char v2, int v3, short v4) :a(v1),b(v2),c(v3),d(v4){}}; /* 16字节 */#elsestruct test{int a;char b;short d;int c;test(int v1, char v2, int v3, short v4) :a(v1),b(v2),c(v3),d(v4){}};/* 12字节 */#endifint main(int argc, char* argv){/*在32位和64位的机器上,size_t的大小不同*/struct test a(1,'a',2,3);printf("the size of struct test is %zu\n", sizeof(a));return 0;}
实验结果如下:
- 16字节内存分布:

- 12字节内存分布:
结论
设计结构体时,合理调整成员的位置,可大大较少存储空间(比如说将内存占用较小的变量顺序放置)
/* 32位机器上执行运行 */struct test{int a;char b;int c;short d;}; /* 大小为16字节 *//* 未对齐 : 0-3 , 4 , 5-8 , 9-10*//* 对齐: 0-3 , 4-7 , 8-11 , 12-15*/struct test{int a;char b;short d;int c;};/* 对齐:0-3 , 4-5 , 6-7 , 8-11 *//* b和d 存储在了同一字节块 */
跨平台通信
由于不同平台对齐方式可能不同,故可采用两种处理方式。
- 1字节对齐
- 主动对结构【字节填充】
1字节对齐
#pragma pack(n)
其内存分布如下(占11字节):#pragma pack(1) /*1字节对齐*/struct test{int a;char b;int c;short d;};#pragma pack()/*还原默认对齐*/
主动填充
不节省空间且扩展性差,不推荐struct test{int a;char b;char reserve[3];int c;short d;char reserve1[2];};
总结
在编程过程中,不需要关注字节对齐的细节,但不可忽略字节对齐,故总结了如下经验:
- 结构体合理安排成员位置
- 跨平台数据可考虑1字节填充
- 本地数据采用默认对齐,以提高访问效率
