串口传输结构体:需要考虑结构体对齐的问题#pragma pack (1)
串口传输结构体:需要考虑结构体对齐的问题,否则会有多出一些乱七八糟的的数据。
#pragma pack(1)99% 的场景都是用在结构体上,核心作用就是:取消字节对齐,让结构体内存紧凑、无空隙、无冗余。
一、#pragma pack (1) 到底是干嘛的?
一句话:让结构体成员之间 “紧贴排列”,不插入任何填充字节(内存对齐空隙)。
默认情况下,C 编译器会对结构体做字节对齐,目的是让 CPU 读取更快,但会浪费内存。#pragma pack(1)就是强制1 字节对齐 = 不浪费任何空间。
二、默认对齐(不用 pack)会产生什么问题?
看这个结构体:
struct Test { char a; // 1 字节 int b; // 4 字节 short c; // 2 字节 };默认对齐下大小 = 12 字节!但实际有效数据只有:1+4+2 =7 字节浪费了5 字节填充!
内存布局是这样的:
a [填充3] b c [填充2] 1B 3B 4B 2B 2B这就是:数据冗余。
三、加上 #pragma pack (1) 之后
#pragma pack(1) // 1字节对齐 struct Test { char a; int b; short c; }; #pragma pack() // 恢复默认对齐大小 = 1+4+2 = 7 字节!没有任何填充,没有任何冗余!
内存布局:
a b c 1B 4B 2B四、为什么要用 #pragma pack (1)?(最关键)
主要用在 3 种场景:
1.串口 / 网络 / 蓝牙 通信协议
发送方和接收方必须结构体内存布局完全一致,不能有填充字节,否则解析错误。
2.读写 Flash / 文件
要保证结构体大小固定,不因为编译器不同而变化。
3.节省内存(嵌入式特别常用)
单片机 RAM 很小,必须紧凑存储。
五、正确写法(必须会)
#pragma pack(1) // 开启1字节对齐 struct MyData { uint8_t head; uint16_t len; uint32_t data; }; #pragma pack() // 关闭,恢复默认对齐一定要成对使用!否则会影响后面所有结构体。
