Мне нужно определить структуру, которая имеет члены данных размером 2 бита и 6 бит.
Должен ли я использовать char
тип для каждого члена? Или, чтобы не тратить память, могу ли я использовать что-то вроде :2
\ :6
нотация?
Как мне это сделать?
Могу ли я определить typedef для типа 2 или 6 бит?
Вы можете использовать что-то вроде:
typedef struct {
unsigned char SixBits:6;
unsigned char TwoBits:2;
} tEightBits;
а затем используйте:
tEightBits eight;
eight.SixBits = 31;
eight.TwoBits = 3;
Но, честно говоря, если вам не нужно соблюдать упакованные данные вне вашего приложения, или вы не в очень Ситуация с ограничением памяти, такого рода экономия памяти обычно не стоит. Вы обнаружите, что ваш код работает намного быстрее, если ему не нужно постоянно упаковывать и распаковывать данные с помощью побитовых и битовых операций.
Также имейте в виду, что использование любого типа, кроме _Bool
, signed int
или же unsigned int
это проблема для реализации. В частности, unsigned char
может не работать везде
Это, вероятно, лучше всего использовать uint8_t
для чего-то вроде этого. И да, использовать битовые поля:
struct tiny_fields
{
uint8_t twobits : 2;
uint8_t sixbits : 6;
}
Я не думаю, что вы можете быть уверены, что компилятор упакует это в один байт. Кроме того, вы не можете знать, как упорядочены биты в байтах, которые занимают значения типа struct. Часто лучше использовать явные маски, если вы хотите больше контроля.
Лично я предпочитаю операторы сдвига и некоторые макросы над битовыми полями, поэтому для компилятора не осталось «волшебства». Это обычная практика во встроенном мире.
#define SET_VAL2BIT(_var, _val) ( (_var) | ((_val) & 3) )
#define SET_VAL6BIT(_var, _val) ( (_var) | (((_val) & 63) << 2) )
#define GET_VAL2BIT(_var) ( (_val) & 3)
#define GET_VAL6BIT(_var) ( ((_var) >> 2) & 63 )
static uint8_t my_var;
<...>
SET_VAL2BIT(my_var, 1);
SET_VAL6BIT(my_var, 5);
int a = GET_VAL2BIT(my_var); /* a == 1 */
int b = GET_VAL6BIT(my_var); /* b == 5 */