单片机/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 的访问效率,但会造成所填字节的浪费,所以为了节省空间,结构体成员最好要按数据类型从大到小排列


相关推荐
Brilliantwxx15 分钟前
【Linux】 进程(10) 进程控制深度解析:创建、终止与等待
linux·运维·服务器·c语言·开发语言·网络
wuyk5551 小时前
从零吃透Modbus通信|第7章:终极工程整合(模块化架构、双模式主机从机、RTOS适配、量产级模板)
c语言·stm32·学习·架构
卢锡荣1 小时前
国产PD3.1全集成Type-C管控芯片LDR6020P
c语言·开发语言
Freak嵌入式1 小时前
Pico UART 数据收发实战:硬件配置、MicroPython 编程
java·开发语言·单片机·嵌入式硬件·生活
Casual1 小时前
【网络基础进阶】:看懂子网划分与 VLAN
开发语言·网络·php
你压到我腿毛了6662 小时前
C语言冒泡算法(Bubble sort)
c语言·数据结构·算法
cfm_29142 小时前
线程池阻塞队列
java·开发语言
xxwxx__3 小时前
C++ list 深度解析:从使用原理到模拟实现
开发语言·c++·list
Freak嵌入式3 小时前
Pico PIO 汇编语法深度详解:标识符、指令、伪指令全解析
汇编·stm32·单片机·嵌入式硬件·fpga开发·硬件架构
Chester_19993 小时前
CSP202303C.LDAP
开发语言·c++·蓝桥杯·stl