Почему не удается скопировать структуру путем прямого назначения?
Я сталкиваюсь с жестким исключением ошибки при копировании некоторых данных на микроконтроллере из одной структуры в другую. Я пробовал разные реализации, которые должны были делать все то же самое. Смотрите мои строки кода:
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 Embedded Toolchain 5.4.1 2016-0919 .
Вот минимальный пример кода, который (надеюсь) показывает проблему. Структура данных 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);
}
Почему не удается скопировать структуру путем прямого назначения?
2 ответа:
При использовании нестандартного
#pragma pack
вы заставляете компилятор хранить структуру без заполнения. Члены структуры передdata
находятся в группах 4+4+3, затемdata
в байте 11, который смещен.Таким образом, вы заставляете
Вопрос в том, почему эта структура изначально упакована, поскольку она не может быть ни отображением аппаратного регистра, ни отображением протокола данных. Такие вещи, как CAN-bus IDE и RTR-это всего лишь отдельные биты; я очень сомневаюсь, что любой контроллер CAN резервирует для этого целый 8-битный регистр. Например, контроллер ST "bxCAN" помещает их как отдельные биты в CAN_TIxR Регистрация (Техас можно зарегистрировать идентификатор почтового ящика). Любой другой контроллер CAN на рынке будет вести себя аналогично.data
всегда выделяться несогласованно, что может вызвать аппаратные исключения на некоторых процессорах, если к нему обращаются как к слову (32 бита). Кодmsg.data = *data;
, созданный компилятором, может предполагать, что при копировании двух структур они всегда правильно выровнены, как это обычно и происходит случай. И наиболее эффективная реализация копии будет работать с 32-битными фрагментами данных, так что это то, что он будет использовать.Что касается самого кадра CAN, вы не можете напрямую сопоставить его с памятью. Контроллер CAN захватит необработанный кадр CAN и поместит его в свои собственные регистры, отображенные в памяти.
Либо переделайте эту структуру без заполнения, либо используйте фактические регистры контроллера CAN, как это предусмотрено вашим оборудованием.
Я обнаружил, что существует регистр CFSR, который содержит информацию о типе жесткого исключения ошибки. Регистр показывает, что бит № 24 установлен. Руководство по программированию АРМ PM0214 гласит на странице 221:
Бит 24 UNALIGNED: ошибка использования Unaligned access. Включить улавливание не выровненный доступ, установив бит UNALIGN_TRP в CCR на 1, см. Регистр конфигурации и управления (CCR) на стр. 214. Несогласованный LDM, СТМ, МЦРУ, и strd успешно инструкции всегда виноват независимо от того, установка UNALIGN_TRP.
0: Нет ошибки доступа без выравнивания или без выравнивания перехват доступа не включен
1: Процессор сделал невыровненный доступ к памяти.
Это действительно соответствует ответу @Lundin.