在C语言里,内存对齐是指编译器在安排变量尤其是结构体成员存放位置时,让它们的起始地址满足一定的倍数关系。这样做主要是为了让CPU能更高效地读写数据,因为很多硬件平台访问未对齐的地址会引发性能下降甚至硬件异常。理解对齐规则并学会手动控制,对编写底层程序非常重要。
什么是内存对齐
现代计算机按字长读取内存,例如32位平台通常一次读4字节。如果某个int类型变量放在地址1开始的位置,CPU可能需要分两次读取才能拼出完整数据。编译器默认会按成员自身大小或平台默认对齐值来排布结构体,于是结构体实际大小常常大于各成员之和。
默认对齐示例
看下面这个结构体,在默认对齐下所占空间并不等于成员相加:
#include <stdio.h>
struct Example {
char a; // 1字节
int b; // 4字节,需要对齐到4的倍数地址
char c; // 1字节
};
int main() {
printf("size = %zun", sizeof(struct Example)); // 通常输出12而非6
return 0;
}
由于b需要4字节对齐,a后面会补3字节空隙,c后面再补3字节让整体是4的倍数,因此大小为12。
如何手动控制结构体的内存对齐
在C语言中,可以通过编译器指令或属性来修改对齐方式,从而节省空间或满足特定协议要求。
使用pragma pack
在MSVC和GCC等编译器里,可用#pragma pack改变后续结构体的对齐值:
#include <stdio.h>
#pragma pack(push, 1) // 设置为1字节对齐
struct Packed {
char a;
int b;
char c;
};
#pragma pack(pop) // 恢复原有对齐
int main() {
printf("size = %zun", sizeof(struct Packed)); // 输出6
return 0;
}
使用aligned和packed属性
GCC还支持属性语法。packed用于取消填充,aligned用于指定最小对齐边界:
#include <stdio.h>
struct Attr {
char a;
int b;
char c;
} __attribute__((packed)); // 紧凑排列,无填充
struct Aligned {
int x;
} __attribute__((aligned(16))); // 按16字节对齐
int main() {
printf("packed size = %zun", sizeof(struct Attr));
printf("aligned size = %zun", sizeof(struct Aligned));
return 0;
}
选择对齐方式的建议
- 网络协议或文件格式解析时常用packed避免空隙,保证字节一一对应。
- 性能敏感且访问频繁的数组可适当对齐到缓存行减少伪共享。
- 修改对齐后应注意某些平台不允许非对齐访问,否则会崩溃。
掌握内存对齐与控制方法,能让你在C语言开发中对空间与效率有更清晰的把握。