内存对齐与填充
内存对齐是硬件架构的要求:某些类型的数据必须存储在特定地址(如 4 字节对齐)。编译器自动插入填充字节(padding)来满足对齐要求。理解对齐规则,可以优化结构体布局、减少内存浪费。
对齐要求
char c; /* 1 字节对齐 */
short s; /* 2 字节对齐 */
int i; /* 4 字节对齐 */
double d; /* 8 字节对齐 */
结构体填充
struct BadLayout {
char c; /* 1 字节 */
/* 3 字节填充 */
int i; /* 4 字节 */
char d; /* 1 字节 */
/* 3 字节填充 */
};
/* sizeof(struct BadLayout) = 12 */
struct GoodLayout {
int i; /* 4 字节 */
char c; /* 1 字节 */
char d; /* 1 字节 */
/* 2 字节填充 */
};
/* sizeof(struct GoodLayout) = 8 */
手动控制对齐
#pragma pack(push, 1) /* 1 字节对齐 */
struct Packed {
char c;
int i;
char d;
};
#pragma pack(pop)
/* sizeof(struct Packed) = 6 */
C11 _Alignas(C99 扩展)
struct Aligned {
char c;
_Alignas(4) int i; /* 4 字节对齐 */
};
计算偏移量
#include <stddef.h>
struct Point {
int x;
int y;
};
printf("%zu\n", offsetof(struct Point, x)); /* 0 */
printf("%zu\n", offsetof(struct Point, y)); /* 4 */
常见错误
假设布局:
struct Data {
char c;
int i;
};
/* 错误假设 sizeof(struct Data) == 5 */
/* 实际是 8(有填充) */
序列化问题:
struct Data d = {'A', 10};
fwrite(&d, sizeof(d), 1, fp); /* 包含填充字节 */
/* 不同平台填充不同,不兼容 */
最佳实践
- 按大小排序成员(大在前)
- 需要紧凑布局时用
#pragma pack - 序列化时逐个成员写入
- 用
offsetof计算偏移 - 不假设结构体布局的可移植性