结构体、数组的联合体对数据包的解包对齐问题
结论:在使用用联合体包装 嵌结构体、和数组,从而对数据数组解包时,结构体的4字节对齐可能会产生解包错误。需要添加1字节对齐指令 __attribute__((packed))
。
如以下数据包:
//数据
unsigned char data1[] = {
0x01,0x00,0xFF,0x48,0x45,0x4C,0x4C,0x4F,0x2E,0x74,0x78,0x74,0x00,0x31,0x31,0x20,
0x31,0x34,0x36,0x33,0x37,0x34,0x36,0x32,0x37,0x37,0x32,0x20,0x30,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x4C,0x1A
};
//数据包共同体
#define PKT_SIZE 128
typedef union
{
// YModem数据包结构
struct {
uint8_t header; // 数据包头部(SOH或STX)
uint8_t blockNumber; // 数据包序号
uint8_t blockNumberC; // 数据包序号的补码
uint8_t data[PKT_SIZE]; // 数据包内容
uint16_t crc; // CRC校验
}UnPack;
uint8_t buff[PKT_SIZE + 5];
}YModemPacketType;
int main()
{
YModemPacketType yModemStruct;
memcpy(yModemStruct.packet.buff,data1,128+5);
printf("%x",yModemStruct.crc);//输出为 0x001a 或0xnn1a
}
结构体默认会对不同类型的变量经行4字节大小的对齐,头三个变量为uint8_t
是同种变量,在内存上是连续的,第四个变量也是uint8_t
,在内存上紧跟前面,但是,由于uint8_t data[128]
是128字节的,后面有紧跟其他类型的变量uint16_t
的UnPack.crc,因此,在UnPack.data[127] 的后面,UnPack.crc 的前面的一个字节内存上,会产生空内存。因此访问UnPack.crc时, 会出现0xNN1A
NN的值不可控。
解决方法:在声明的结构体前面使用__attribute__((packed))
的按字节对齐命令,
其他命令:__attribute__((aligned(4)))
按四字节对齐。
typedef union
{
// YModem数据包结构
struct __attribute__((packed)){
uint8_t header; // 数据包头部(SOH或STX)
uint8_t blockNumber; // 数据包序号
uint8_t blockNumberC; // 数据包序号的补码
uint8_t data[PKT_SIZE]; // 数据包内容
uint16_t crc; // CRC校验
};
uint8_t buff[PKT_SIZE + 5];
}YModemPacketType;
int main()
{
YModemPacketType yModemStruct;
memcpy(yModemStruct.buff, data1, sizeof(data1));
printf("%x",yModemStruct.crc);//输出为 1a4c 电脑和STM32是小端模式,数据低位在地址低位
return 0;
}
关于作者:赤诚Xie
版权声明:本博客所有文章仅用于学习、交流和研究目的,欢迎转载,但请注明原文作者及出处。
奥里给!:若您觉得文章对您有帮助,请点赞、关注支持我吧😊。
药药切克闹,👇👇👇下面三连来一套(●'◡'●)
——励志作一个用单片机梳头的乖宝宝
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下