Использование полубайтов (4-битных переменных) в Windows C / C ++ - PullRequest
19 голосов
/ 14 мая 2009

Я программирую сетевые заголовки, и многие протоколы используют 4-битные поля. Есть ли удобный тип, который я могу использовать для представления этой информации?

Самый маленький тип, который я нашел, это БАЙТ. Затем я должен использовать множество бинарных операций для ссылки только на несколько битов внутри этой переменной.

Ответы [ 5 ]

33 голосов
/ 14 мая 2009

Поскольку память имеет адрес в байтах, вы не можете адресовать ни одну единицу, меньшую, чем один байт. Однако вы можете создать struct, который хотите отправить по сети, и использовать битовые поля , например:

struct A {
   unsigned int nibble1 : 4;
   unsigned int nibble2 : 4;
};
15 голосов
/ 14 мая 2009

Расширяя ответ Mehrdads, также используйте союз с байтом, чтобы избежать некоторых зловредных приведений:

union Nibbler {
     struct { 
        unsigned int first:4;
        unsigned int second:4;
     } nibbles;
     unsigned char byte_value;
}
6 голосов
/ 14 мая 2009

Всем, кажется, нравится использовать битовые поля в struct s для этого. Лично я оборачиваю весь свой пакетный код в объекты, чтобы вы не видели смелости. Проблема, которую я обнаружил при использовании битовых полей для кода протокола, заключается в том, что он поощряет использование структур в качестве наложений на память. Вы можете сделать это безопасно, но вы должны быть крайне осторожны, чтобы убедиться, что вы правильно справляетесь с проблемами порядка и упаковки. Если у вас нет веской причины (например, вы пишете код, который получает пакет Ethernet из области ввода-вывода с отображением в памяти), то использование битовых полей, наложенных на память, приводит к крайне хрупкому коду IMHO.

Мне гораздо проще написать класс Packet, который реализует процедуры извлечения, вставки и перезаписи с разной шириной в битах. Затем вы реализуете свой код обработки пакетов с точки зрения извлечения значений определенной ширины из смещений в собственные целые числа, а что нет. Скрывайте все абстракции и проблемы упаковки за абстракцией до тех пор, пока профилирование не покажет, что накладные расходы слишком велики, чтобы их нести.

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

3 голосов
/ 14 мая 2009

Использовать поля в структуре:

struct Header
{
    unsigned int lowestNibble : 4;
    unsigned int anotherNibble : 4;
    unsigned int : 18;                 # Unnamed padding.
    bool aBool : 1;
    bool anotherBool : 1;
    unsigned int highestNibble : 4;
};

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

Обычно вы в конечном итоге приводите указатель на ваши данные к Header *, а затем делаете что-то вроде:

pHeader->lowestNibble = 5;
0 голосов
/ 14 мая 2009

Нет, удобных типов для клевов нет. Но их легко сделать с помощью макросов или шаблонных функций. Это хорошо работает, особенно если / когда вам нужно иметь дело с порядком байтов.

Foredecker

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