реклама на сайте
подробности

 
 
> Приём/передача незапакованной структуры для C2000, Программерская смекалка :)
sigmaN
сообщение Oct 26 2009, 12:59
Сообщение #1


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



Код
typedef uint32_t ba05_blockKey[BA05_BLOCKKEYSIZE];

//заголовок у обоих типов пакетов общий, поэтому опишем его один раз
struct ba05_net_pktHeader
{
    uint16_t    packetType    : 3;    //ID-пакет, BlockPacket или HeaderPacket
    uint16_t    connStageID    : 3;    //public_keys_interchange, random_sample_interchange, hash_interchange
    uint16_t    needACK        : 1;    //сообщает приёмнику, что в ответ на этот пакет нужно обязательно отправить ACK пакет
    uint16_t    ACK            : 1;    //Признак пакета подтверждения. Если ACK==1 - все остальные поля не используются(кроме crc8,естественно)    
    uint16_t    crc8         : 8;
};
//описание поля data для пакета IDPacket
struct ba05_net_IDPacket_data
{
    ba05_ID                public_ID;    
    ba05_ID                corp_ID;    
};
//поле data для Block-пакета описано в объявлении ba05_net_packet ниже
typedef struct
{
    struct ba05_net_pktHeader             header;
    union
    {
        struct ba05_net_IDPacket_data     asIDPacket;
        ba05_blockKey                asBlockPacket;
    }data;
}ba05_net_packet;

Прагмы, заставляющей компилятор запаковать структуру - нет.
Тип ba05_blockKey может изменяться в зависимости от настроек алгоритма. Т.е. вместо uint32_t там может появиться uint16_t или uint64_t, соответственно, выравнивание будет разным.
На данный момент, не сложно догадаться, после header идёт пустышка(1слово), длее идёт data.
Если бы структура передавалась всегда полностью - проблем бы не было. Но в зависимости от ситуации, передаётся либо только header, либо header + asIDPacket, либо целиком(header + asBlockPacket).
Функции отправки/приёма анализируют header.packetType и по нему определяют сколько байт нужно отправить/принять(а также обработать при пересчёте CRC).
И всё было-бы хорошо, если бы не тот факт, что из-за пустышек, применяемых для выравнивания, сумма sizeof всех полей получается меньше sizeof всей структуры.
Как я уже говорил, настройки могут меняться и нужно это дело как-то обработать универсальным способом.
На данный момент я сделал так:
Код
*/
*    Ниже, я постарался обработать эту ситуацию с помощью препроцессора и арифметики с указателями.
*    Суть в том, что вместо sizeof я применял разность адресов .data и .header
*    оператор взятия адреса(&) позволит нам уловить момент вставки компилятором пустышки
*    пример: <header size=1byte,address=0><пустышка size=1byte,address=1><data size=2,address=2>
*    если просто взять sizeof(header) + sizeof(data) байт и отправить - то мы отправим header полностью
*    пустышку полностью, а поле data будет передано не полностью(на sizeof(пустышка) байт меньше)
*    Но если я вместо sizeof(header) использую (&data -  &header) то пустышка будет учтена.
*/
enum {  HeaderPacketSize = sizeof(((ba05_net_packet *)0)->header) }; //header сам по себе никуда не выравнивается
//а дальше пришлось мудрить
#define BlockPacketSize ( ((int)&((ba05_net_packet *)0)->data.asBlockPacket - (int)&((ba05_net_packet *)0)->header) + sizeof(((ba05_net_packet *)0)->data.asBlockPacket) )
#define IDPacketSize ( ((int)&((ba05_net_packet *)0)->data.asIDPacket - (int)&((ba05_net_packet *)0)->header) + sizeof(((ba05_net_packet *)0)->data.asIDPacket) )

//теперь нам нужно правильно определить размер в байтах
#ifdef SIZEOF_IS_IN_WORDS
    enum {  HeaderPacketSize_bytes = HeaderPacketSize * 2    };
    #define BlockPacketSize_bytes ( BlockPacketSize * 2 )
    #define    IDPacketSize_bytes ( IDPacketSize * 2 )
#elif defined(SIZEOF_IS_IN_BYTES)
    enum {  HeaderPacketSize_bytes = HeaderPacketSize        };
    #define BlockPacketSize_bytes ( BlockPacketSize )
    #define    IDPacketSize_bytes ( IDPacketSize )
#endif

Работает. Но как-то мудрёно получается....
Прокомментируйте решение, пожалуйста. Что можно поменять? Как сделать проще/лучше?

P.S. SIZEOF_IS_IN_WORDS/SIZEOF_IS_IN_BYTES тут присутствуют для обеспечения портируемости. Дело в том, что мой компилятор возвращает sizeof в словах(по 2 байта). Побайтового доступа к памяти нет.
Однако, при работе с сетью нам нужны байты. На других архитектурах, где sizeof() ведет себя прилично - этой проблемы не будет. Поэтому я обрабатываю эту ситуацию отдельно.
А функции отправки/приёма просто могут использовать *_bytes и не беспокоиться не о чём smile.gif


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 20:29
Рейтинг@Mail.ru


Страница сгенерированна за 0.01348 секунд с 7
ELECTRONIX ©2004-2016