Битовые поля и союзы в C, создающие проблемы
Я внедряю стандарт радиосвязи и столкнулся с проблемой союзов в структуре и объеме памяти. В приведенном ниже примере мне нужно, чтобы эта структура находилась в одном байте памяти (согласно стандарту радиосвязи), но в настоящее время она дает мне размер 2 байта. После долгих раскопок я понимаю, что это потому, что "размер" Union - это байт, а не 3 бита... но пока не удалось обойти это. Я посмотрел на:
- Битовые поля в C со структурой, содержащей объединение структур; а также
- Будет ли это битовое поле работать так, как я ожидаю?
Но ни один из них, похоже, не дает мне решения.
Есть идеи?
Спасибо!
#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++.