单片机/C/C++八股:(十五)内存对齐、结构体内存对齐

上一篇 下一篇
const 关键字的作用(和 define 比呢?)

目 录


内存对齐、结构体内存对齐

视频教学连接:CPU 到底是怎么读内存的?十分钟搞懂内存对齐_哔哩哔哩_bilibili

1)分析讲解

一切的根本原因是:

CPU 从内存中读取数据,32 位系统一次会读取 32 位(4字节),64 位系统一次会读取 64 位(8字节),以 32 位系统为例:一次读 4 字节,就意味着从 0 地址开始的话,每次都会从 4 的整数倍地址处开始读。

所以为了保证读取效率和兼容性,数据存储的时候,会自动进行内存对齐,实现内存对齐的方式是在变量值之间填充字节(padding)

数据不进行内存对齐的话,就需要读取多次才能拼出完整的值:

内存对齐规则:

数据类型的大小,就是它的对齐边界(数据类型占 n n n 个字节,那么其起始地址就必须存放在 n n n 的倍数地址上)

比如在 32 系统中:

  • char 对齐边界:1字节(任意地址);
  • short 对齐边界:2字节(偶数地址);
  • int / float 对齐边界:4字节(4的倍数地址);
  • double 对齐边界:8字节(8的倍数地址)。

内存对齐是通用的 硬件/ABI 要求,不仅限于结构体,主要考察结构体内存对齐还有另一个原因 ⟶ \longrightarrow ⟶

结构体的特性:

结构体的大小,必须是占内存最大成员的整数倍。

核心原因:为了支持结构体数组的正确内存布局,确保结构体数组中每一个元素的起始地址都满足其内部成员的对齐要求,从而保证程序在所有平台上正确、高效运行。

具体来说:假设定义了一个结构体 S,并声明一个数组:struct S arr[2]; ,结构体数组元素在内存中是紧挨着的,即 &arr[1] == &arr[0] + sizeof(struct S),为了让 arr[1] 中的每个成员也依然满足对齐要求sizeof(struct S) 必须是一个"安全步长",这个步长必须能保证下一个结构体实例的起始地址,仍然满足其内部所有成员的对齐约束。而这个"安全步长"的最小值,就是 结构体中最大成员的对齐要求 ,也就是结构体的大小,必须是占内存最大成员的整数倍。为了达到这个效果,编译器会在结构体尾部填充字节。

以如下结构体为例:

c 复制代码
struct BadStudent
{
	char grade;		// 1字节
	int id;			// 4字节
	char gender;	// 1字节
};

以为是 1+4+1=6 字节,实际上是 12 字节:先内存对齐到 1+(3)+4+1=9 字节 → 再填充字节到 int 型的整数倍 12 字节。

缺点及优化方法:

  • 缺点:内存对齐会导致填充字节无法使用,造成内存浪费。

  • 方法:结构体成员按数据类型从大到小排列(如果定义了一个 char 型的数组,那这个数组不用放在最前面,单个元素只是 char ,但数组长度可能会造成一定的影响)。

还以那个结构体为例,其元素换个顺序:

c 复制代码
struct BadStudent
{
	int id;			// 4字节
	char grade;		// 1字节
	char gender;	// 1字节
};

现在实际上占用 4+1+1=6 → 8 字节。

2)总结

内存对齐源于 CPU 根据系统位数按固定字长(如 4 或 8 字节)高效读取内存的机制,要求数据起始地址为其类型大小的整数倍。

内存对齐的规则:数据类型占 n n n 个字节,那么其起始地址就必须存放在 n n n 的倍数地址上(32/64位系统中,数据类型所占字节数不同)。

而为了确保结构体数组中每一个元素的起始地址都能满足其内部成员的对齐要求,所以结构体的大小,必须是占内存最大成员的整数倍

虽然内存对齐提高了 CPU 的访问效率,但会造成所填字节的浪费,所以为了节省空间,结构体成员最好要按数据类型从大到小排列


相关推荐
Scott9999HH8 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社9 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海9 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖10 小时前
JDK 26 新特性详解
java·开发语言
马优晨10 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区12 小时前
怎么把C语言学到精通?
c语言·开发语言
sramdram12 小时前
MCU微控制器OA打印机方案
单片机·嵌入式硬件·mcu·mcu微控制器
心平气和量大福大13 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai13 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜13 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript