当我将 micro-controller 上的某些数据从一个结构体复制到另一个结构体时,我遇到了 Hard Fault 异常。 我尝试了不同的实现方式,它们应该都是相同的。请参阅我的代码行:
memcpy(&msg.data, data, 8);
memcpy(&msg.data, data, sizeof(*data));
memcpy(&msg.data, data, sizeof(msg.data));
msg.data = *data; // Hard Fault
前三行工作得很好。最后一行以一个硬件错误异常结束。使用 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嵌入式工具链5.4.1 20160919。
这里是一个最简代码示例,它(希望)展示了问题。数据结构msg_t
必须使用packed
属性来匹配一些硬件寄存器。在微控制器上,这段代码将在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);
}
为什么通过直接赋值复制结构会失败?
msg
的类型是什么? - Jabberwockydata
字段中,因为通常编译器会使用适当的填充,但仍然尝试找出offsetof
告诉你的内容。 - Jabberwockypragma pack
文档应该提到这个问题。 - M.M