Битовые поля и союзы в C, создающие проблемы

Я внедряю стандарт радиосвязи и столкнулся с проблемой союзов в структуре и объеме памяти. В приведенном ниже примере мне нужно, чтобы эта структура находилась в одном байте памяти (согласно стандарту радиосвязи), но в настоящее время она дает мне размер 2 байта. После долгих раскопок я понимаю, что это потому, что "размер" Union - это байт, а не 3 бита... но пока не удалось обойти это. Я посмотрел на:

Но ни один из них, похоже, не дает мне решения.

Есть идеи?

Спасибо!

#ifdef WIN32
#pragma pack(push)
#pragma pack(1)
#endif

typedef struct three_bit_struct
{
    unsigned char bit_a : 1;
    unsigned char bit_b : 1;
    unsigned char bit_c : 1;
}three_bit_struct_T;


typedef union
{
    three_bit_struct_T three_bit_struct;
    unsigned char another_three_bits : 3;
}weird_union_T;


typedef struct
{
    weird_union_T problem_union; 
    unsigned char another_bit : 1;
    unsigned char reserved : 4;
}my_structure_T;


int _tmain(int argc, _TCHAR* argv[])
{
     int size;

     size = sizeof(my_structure_T);

     return 0;
}


#ifdef WIN32
#pragma pack(pop)
#endif

2 ответа

Проблема в том, что размер three_bit_struct_T будет округлен до ближайшего байта* независимо от того, что он содержит только три бита в своем битовом поле. Структура просто не может иметь размер, который является частью байта. Поэтому, когда вы увеличиваете его с помощью дополнительных полей в my_structure_Tнеизбежно размер будет перетекать во второй байт.

Чтобы собрать все эти вещи в один байт, вам нужно поместить все элементы битового поля во внешний my_structure_T вместо того, чтобы иметь их в качестве внутренней структуры / объединения.

Я думаю, что лучшее, что вы можете сделать, это объединить все это.

typedef struct
{
    unsigned char bit_a : 1;
    unsigned char bit_b : 1;
    unsigned char bit_c : 1;
    unsigned char another_bit : 1;
    unsigned char reserved : 4;
} three_bit_struct_T;

typedef struct
{
    unsigned char another_three_bits : 3;
    unsigned char another_bit : 1;
    unsigned char reserved : 4;
} another_three_bit_struct_T;

typedef union
{
    three_bit_struct_T three_bit_struct;
    another_three_bit_struct_T another_three_bit_struct;
} my_union_T;

(*) или слово, в зависимости от настроек выравнивания / упаковки.

Два полезных совета: никогда не используйте struct/union для протоколов данных и никогда не используйте битовые поля в любой ситуации.

Лучший способ реализовать это - использовать битовые маски и побитовые операторы.

#define BYTE_BIT7 0x80u

uint8_t byte;

byte |= BYTE_BIT_7;  // set bit to 1
byte &= ~BYTE_BIT_7; // set bit to 0

if(byte & BYTE_BIT_7) // check bit value

Этот код переносим на любой компилятор C в мире, а также на C++.

Другие вопросы по тегам