Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Работа с упакованными структурами (Си, ARM9)
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Harvester
ARM9, компилятор ADS 1.2

Имеется упакованная структура, которая приходит/уходит по интерфейсу, т.е. от упаковки никуда не деться.
Код
typedef __packed struct {
  uint16    params_len;
  uint8     params_data[PARAMS_MAX_SIZE];
  uint16    in_data_len;
  uint16    out_data_len;
} pkt_type;

При передаче в функию указателя как на поле структуры
Код
send_req(..., &input_pkt.params_data[0])

так и на саму структуру
Код
memset(&input_pkt, 0, PACKET_SIZE)

компилятор выдает ошибку
Error: C2906E: <argument x to 'xxxxx'>: implicit cast of pointer loses '__packed' qualifier
Т.е. при взятии адреса упакованной структуры или ее элемента упаковка не учитывается. sad.gif

Как можно обойти такое поведение компилятора?
Я пока вижу только такой выход:
Определить массив
Код
uint8 raw_packet[PACKET_SIZE];

набор констант
Код
#define PARAMS_LEN_OFS   0
#define PARAMS_LEN_TYPE  uint16
...

и обращаться к массиву
Код
params_len = (PARAMS_LEN_TYPE)raw_packet[PARAMS_LEN_OFS];


Может есть более изящное решение?

UPD:
При явном преобразвании к char *
Код
memset((char *)&input_pkt, 0, PACKET_SIZE)

ошибка пропадает
_pv
Цитата(Harvester @ Nov 13 2013, 15:23) *
Я пока вижу только такой выход:
Определить массив
Код
uint8 raw_packet[PACKET_SIZE];

набор констант
Код
#define PARAMS_LEN_OFS   0
#define PARAMS_LEN_TYPE  uint16
...

и обращаться к массиву
Код
params_len = (PARAMS_LEN_TYPE)raw_packet[PARAMS_LEN_OFS];

Может есть более изящное решение?

это не правильно, надо
Код
params_len = *(PARAMS_LEN_TYPE *) &raw_packet[PARAMS_LEN_OFS];

иначе он 16 бит из 8ми разрядного raw_packet[PARAMS_LEN_OFS] не достанет.
при этом, не знаю догадается ли компилятор что адреса могут быть не выровнены.

можно в макрос завернуть, который еще и endianess может менять если надо.
но за типами данных самому следить тогда надо.
#define UNPACK16(buff,offset) ((u16)buff[offset] + (u16)buff[offset+1] << 8)
params_len = UNPACK16(raw_packet,PARAMS_LEN_OFS);

aaarrr
Цитата(Harvester @ Nov 13 2013, 12:23) *
При явном преобразвании к char *
Код
memset((char *)&input_pkt, 0, PACKET_SIZE)

ошибка пропадает

Это и есть более изящное решение: использовать явное преобразование типа там, где структура нужна не в виде структуры, а в виде последовательности байтов (тот же memset, прием/передача по интерфейсу).
Harvester
Цитата(aaarrr @ Nov 13 2013, 14:37) *
Это и есть более изящное решение: использовать явное преобразование типа ...

Тогда уже теоретический вопрос: почему явное преобразование годится, а неявное - генерирует ошибку?
У memset тип 1-го параметра вообще void * (внутри функции он приводится к char *). Мне всегда казалось, что применение void подразумевает автоматическую совместимость с любым типом.
aaarrr
Наверное, таково видение создателей компилятора - напоминать при любом неявном преобразовании упакованного типа. Все же это надстройка.
GetSmart
Или недоработка. Но, возможно, ошибка - выдавать Error при присваивании типу void * адреса из того же пространства, но с атрибутом внутреннего/внешнего выравнивания. Явным преобразованием можно по ошибке отключить ключевые квалификаторы адресного пространства или типа доступа, вроде volatile, __code, __data и прочие платформозависимые.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.