1. 内存对齐的前世今生
第一次遇到内存对齐问题是在2013年做嵌入式开发时,一个结构体在x86和ARM平台表现不一致导致系统崩溃。当时调试了整整两天才发现是内存对齐惹的祸。这个问题看似简单,却困扰着无数开发者,特别是在跨平台开发、网络通信和硬件交互场景中。
内存对齐的本质是CPU访问内存的一种优化策略。现代处理器通常不会按字节访问内存,而是以2、4、8、16字节为单位进行存取。当数据按这些边界对齐时,CPU只需一次内存操作即可完成读取;否则可能需要两次操作并对结果进行拼接,严重影响性能。举个例子,假设一个int变量存储在地址0x0003,32位CPU需要先读取0x0000-0x0003,再读取0x0004-0x0007,最后拼接出完整数值。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. #pragma pack的魔法与陷阱
2.1 编译器默认对齐规则
不同编译器有各自的对齐规则。以gcc为例,默认遵循"自然对齐"原则:
- char: 1字节对齐
- short: 2字节对齐
- int/float: 4字节对齐
- double/long long: 8字节对齐
- 指针: 32位系统4字节,64位系统8字节
c复制struct Example {
char a; // 偏移0,大小1
int b; // 偏移4(跳过3字节),大小4
double c; // 偏移8,大小8
}; // 总大小16
2.2 #pragma pack的使用姿势
#pragma pack(n)指令用于强制改变对齐方式,n取值通常为1/2/4/8/16。这个指令会影响其后所有结构体的内存布局,直到遇到另一个#pragma pack或#pragma pack()恢复默认。
c复制#pragma pack(1)
struct PackedExample {
char a; // 偏移0
int b; // 偏移1
double c; // 偏移5
}; // 总大小13
#pragma pack()
警告:过度使用pack(1)会导致性能下降,在x86上可能有10%-30%的性能损失,在ARM
