Как я представляю битовую информацию в C? - PullRequest
5 голосов
/ 07 августа 2010

Мне нужно хранить значение от 0 до 15 в C, для этого достаточно 4 бит.Как я могу просто иметь переменную 4 бита?Пространство является здесь ограничением

Ответы [ 6 ]

7 голосов
/ 07 августа 2010

Рассмотрите возможность использования char. Да, это 8 бит, но вы можете использовать операторы сдвига битов (<< и >>) для хранения значений в других 4 битах.

Редактировать: Согласно комментариям ниже, unsigned char, на самом деле, предпочтительнее, чем char, чтобы избежать проблем со знаковым битом.

4 голосов
/ 07 августа 2010

Вы можете использовать битовое поле для хранения ваших 4 битов, однако, если вы не используете несколько из них, смежных в структуре, вы не сэкономите место при хранении значения в байте.

3 голосов
/ 07 августа 2010

Вы не можете иметь одну 4-битную переменную, но вы можете иметь 8-битные переменные, которые хранят два 4-битных значения, но вы должны обращаться к ним с помощью временного значения, то есть вы не экономите место, если только у вас больше двух:

uint8_t var_both;
uint8_t temp = (var_both >> 4) & 0x0F; // For first value
temp = var_both & 0x0F; // For second value
2 голосов
/ 07 августа 2010

Как указал Крис Латс, вы можете определить количество битов, которые использует переменная, добавив двоеточие и его размер: unsigned char myOneBitVariable:1; и для вашего случая 'unsigned char MyFourBitVariable: 4'. Я хотел бы указать, как чрезвычайно сложно это и почему вы должны избегать этого .

Большинство современных компиляторов выравнивают пространство для ваших переменных в вашей структуре. Наиболее общий случай сегодня составляет 4 байта или даже 8 байтов, но это варьируется от платформы к платформе и от компилятора до компилятора. Некоторые компиляторы позволяют указывать выравнивание данных и их членов. В GCC ключевое слово __attribute__((aligned(x))), а в MSVC - __declspec(align(x)). В большинстве случаев вам также нужно будет указать, сколько компилятор должен упаковать структуры. MSVC имеет директиву #pragma pack(x): http://msdn.microsoft.com/en-us/library/2e70t5y1(VS.80).aspx. Вы также можете прочитать о выравнивании MSVC здесь: http://msdn.microsoft.com/en-us/library/83ythb65(VS.80).aspx. GCC имеет свою собственную реализацию под названием __attribute__ ((__packed__), которую вам, возможно, придется искать. Пример, который не дает вам того, что вы хотите, используя компилятор Microsoft:


#ifndef _MSC_VER
#error This alignment solution / packing solution is only valid on MSC
#endif /* ifndef _MSC_VER */

#define M_ALIGN(x)    __declspec(align(x))

struct S64Bits
{
    unsigned char MyOneBitVariable:1;
    int My32BitInt;
};

// MSVC specific implementation of data-packing in a type.
#pragma pack(1)
struct S32Bits
{
    D_ALIGN(1) int My16BitVariable:16;
    D_ALIGN(1) unsigned char Padding8Bits;
    D_ALIGN(1) unsigned char MyOneBitVariable1:1;
    D_ALIGN(1) unsigned char MyOneBitVariable2:1;
    D_ALIGN(1) unsigned char MyOneBitVariable3:1;
    D_ALIGN(1) unsigned char MyOneBitVariable4:1;
    D_ALIGN(1) unsigned char MyFourBitVariable:4;
};
#pragma pack(pop)

'sizeof (S64Bits)' должен быть 8, что и есть. sizeof (S32Bits) должен быть 4, это не . На MSVC последний составляет 6 байтов. Поведение также зависит от компилятора и часто имеет уникальные для компилятора директивы. Такое поведение почти никогда не дает вам то, что вы хотите. Я часто использую макрос, чтобы убедиться, что структуры, которые мне требуются, имеют определенный размер:


#define TEST_TYPE_SIZE(Type, Size) assert(sizeof(Type) == Size);

Что я буду использовать ниже всех своих типов данных, где я пытаюсь указать их точный размер. Однако полагаться на то, что структура имеет любой размер, отличный от sizeof (mystructure), - это кодирование, которое, вероятно, приведет к трудностям при отладке ошибок. Директивы компилятора выравнивания лучше всего подходят для выравнивания данных по размеру строки кэша и аналогичным проблемам эффективности.

Карл Билефельдт (Karl Bielefeldt) предлагает хорошее естественное решение для хранения 4-битных значений в uint8 с использованием операций сдвига битов, используйте их вместо этого.

0 голосов
/ 07 августа 2010

Вы когда-нибудь захотите взять адрес 4-битных значений?Если это так, вам нужно хранить их в «правильном» типе данных, таком как char.

0 голосов
/ 07 августа 2010

Термин для полубайта - это клев. Итак, здесь:

struct two_nibbles {
  unsigned a :4;
  unsigned b :4;
}

Вам нужно назвать две переменные x.a и x.b (но изменить x на что угодно), но вы сэкономите немного места. Вы, возможно, захотите проверить, хотя - я думаю, что компилятор позаботится о sizeof(struct two_nibbles) == sizeof(char), но это может и не произойти, поэтому вам, возможно, придется добавить больше кусков, чтобы оно стоило места.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...