Keil中强转结构体的uint8_t数组为uint16_t触发HardFault如何解决
问题根因
该问题是典型的ARM架构非对齐访问异常:
Cortex-M系列内核默认要求访问16位/32位变量时,地址必须对应对齐(uint16_t地址必须是2的整数倍,uint32_t必须是4的整数倍),非对齐访问会直接触发HardFault。
你第一种写法中单独定义的uint8_t数组,编译器默认会分配到对齐到至少2字节的内存地址,强转访问不会出问题;但结构体中data数组前面有3个连续的uint8_t成员,总偏移量为3,导致data数组的起始地址是奇数,强转成uint16_t*访问就触发了非对齐异常。x86架构默认支持非对齐访问,所以在线编译器运行正常。
解决方案
- 方案1(最推荐,跨平台兼容):使用
memcpy拷贝数据,不需要移位操作,也不会触发对齐问题,性能开销极小,是串口报文解析的通用方案
#include <string.h> uint16_t val; memcpy(&val, receivedData.data, sizeof(val));
- 方案2(依赖Keil编译环境):给结构体添加
__packed修饰符,告诉编译器自动处理非对齐访问,无需修改访问逻辑
typedef __packed struct { uint8_t address; uint8_t opID; uint8_t dataLen; uint8_t data[250]; uint8_t crc[2]; }MODBUS;
添加__packed后,编译器不会在结构体成员之间插入填充字节,访问非对齐指针时会自动拆分为多次单字节访问,避免触发硬件异常。
- 方案3(无编译依赖):手动调整结构体成员偏移,让
data数组满足对齐要求
在dataLen和data之间添加1字节保留位,让data的起始偏移变为4,满足2/4字节对齐要求:
typedef struct { uint8_t address; uint8_t opID; uint8_t dataLen; uint8_t reserved; // 填充字节,调整对齐 uint8_t data[250]; uint8_t crc[2]; }MODBUS;
该方案无需依赖编译器扩展语法,但需要注意报文的字节偏移要对应调整。
内容的提问来源于stack exchange,提问作者alig24
相关产品推荐
相关产品推荐

