将微 Controller 上的某些数据从一个结构复制到另一个结构时,我遇到了“硬故障”异常。我尝试了应该完全相同的不同实现。看我的代码行:
memcpy(&msg.data, data, 8);
memcpy(&msg.data, data, sizeof(*data));
memcpy(&msg.data, data, sizeof(msg.data));
msg.data = *data; // Hard Fault
前三行工作正常。最后一个以Hard Fault Exception结尾。带有
memcpy
的行的程序集是相同的。直接分配的程序集有所不同: memcpy(&msg.data, data, sizeof(msg.data));
800c480: f107 030c add.w r3, r7, #12
800c484: 330b adds r3, #11
800c486: 2208 movs r2, #8
800c488: 6879 ldr r1, [r7, #4]
800c48a: 4618 mov r0, r3
800c48c: f7f4 f82e bl 80004ec <memcpy>
msg.data = *data; // Hard Fault
800c490: 687b ldr r3, [r7, #4]
800c492: f107 0217 add.w r2, r7, #23
800c496: cb03 ldmia r3!, {r0, r1}
800c498: 6010 str r0, [r2, #0]
800c49a: 6051 str r1, [r2, #4]
我正在使用GNU Arm Embedded Toolchain 5.4.1 20160919。
这是一个最小的代码示例(希望)显示该问题。数据结构
msg_t
必须使用packed
属性来匹配某些硬件寄存器。在微 Controller 上,此代码在hardt错误处以msg.data = *data;
结尾#include <stdint.h>
#include <string.h>
#include <stdio.h>
typedef struct canData_s {
uint8_t d1;
uint8_t d2;
uint8_t d3;
uint8_t d4;
uint8_t d5;
uint8_t d6;
uint8_t d7;
uint8_t d8;
} canData_t;
#pragma pack(push, 1)
typedef struct msg_s {
uint32_t stdId;
uint32_t extId;
uint8_t ide;
uint8_t rtr;
uint8_t dlc;
canData_t data; // 8 Bytes
uint8_t navail; // not available
uint32_t timestamp;
} msg_t;
#pragma pack(pop)
void setData(canData_t *data) {
msg_t msg;
msg.data = *data;
// Do something more ...
printf("D1:%d", msg.data.d1);
// ...
}
int main() {
canData_t data;
memset(&data, 0, 8);
setData(&data);
}
为什么通过直接分配复制结构失败?
最佳答案
当您使用非标准的#pragma pack
时,您将强制编译器存储该结构而无需任何填充。 data
之前的struct成员是4 + 4 + 3的组,然后是字节11处的data
,这是未对齐的。
因此,您必须强制data
始终分配为未对齐状态,如果将其作为一个字(32位)进行访问,则可能会导致某些CPU出现硬件异常。编译器生成的代码msg.data = *data;
可能假定复制两个结构时,它们始终正确对齐,通常是这种情况。副本的最有效实现将处理32位数据块,因此将使用该副本。
这里的问题是为什么要打包此结构,因为它既不能是硬件寄存器映射,也不能是数据协议(protocol)映射。诸如CAN-bus IDE和RTR之类的东西都只是一位。我非常怀疑任何CAN Controller 都为此预留了一个完整的8位寄存器。例如,ST的“bxCAN” Controller 将它们作为单独的位放置在CAN_TIxR寄存器(CAN TX邮箱标识符寄存器)中。市场上的其他所有CAN Controller 的行为也将相似。
至于CAN框架本身,您不能直接对其进行内存映射。 CAN Controller 将抓取原始CAN帧并将其放置在其自己的内存映射寄存器中。
无需填充即可重新构建此结构,或使用硬件提供的实际CAN Controller 寄存器。
关于c - 为什么通过直接分配复制结构失败?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48745111/