Как читать и записывать биты в байтовый массив
Вопрос
У меня есть unsigned char буфер, и мне интересно, как я буду писать и читать биты со знаком и без знака в этот байтовый буфер.
В Source Engine есть класс с именем bf_write , в котором два основных метода (используются WriteString, WriteChar, WriteLong и т. д.) используют две функции с именем > WriteUBitLong и WriteSBitLong .
Заранее спасибо
Решение
Если число битов является постоянной времени компиляции:
#include <bitset>
...
std::bitset<100> b;
b[2]=true;
Если это не так, используйте Boost.dynamic_bitset р>
Или, если вы в отчаянии, std :: vector, который действительно является упакованным битовым вектором:
#include <vector>
...
std::vector<bool> b(100);
b[2]=true;
Похоже, вы хотите использовать библиотеку, в которой требуются битовые векторы, упакованные в массив байтов. Не зная точно, в каком порядке он размещает биты, я могу только отметить, что:
1) все вышеперечисленное, вероятно, будет использовать как минимум 32-битные целые числа с битами, упорядоченными наименьшим - > большинство или большинство - > наименее значимый
2) на процессорах с прямым порядком байтов (Intel / AMD) это означает, что память, занимаемая байтами массива int, может не соответствовать порядку битов в int. если это " бит 0 - это lsb для int 0, ... бит 32 - это lsb для int 1, ... " то же самое относится к младшему порядкову байтов как " бит 0 - это lsb char 0, ... bit 32 - это lsb char 4 ... " в этом случае вы можете просто привести указатель на массив int на указатель на массив char
3) предположим, что родной порядок байтов в вашем наборе битов / векторе не совсем то, что нужно библиотеке, тогда вам нужно либо создать свой собственный, имеющий желаемый макет, либо записать копию в свой макет , Р>
a) если порядок битов в байте отличается, то таблица поиска с 256 входами, предоставляющая байт с обращенными битами, будет эффективной. Вы можете сгенерировать таблицу с помощью небольшой процедуры.
б) для обращения байтов от маленьких < - > big endian:
inline void endian_swap(unsigned short& x)
{
x = (x>>8) |
(x<<8);
}
inline void endian_swap(unsigned int& x)
{
x = (x>>24) |
((x<<8) & 0x00FF0000) |
((x>>8) & 0x0000FF00) |
(x<<24);
}
inline void endian_swap(unsigned long long& x)
{
x = (x>>56) |
((x<<40) & 0x00FF000000000000) |
((x<<24) & 0x0000FF0000000000) |
((x<<8) & 0x000000FF00000000) |
((x>>8) & 0x00000000FF000000) |
((x>>24) & 0x0000000000FF0000) |
((x>>40) & 0x000000000000FF00) |
(x<<56);
}
Чтобы получить / установить определенный бит в слове, с битом 0 в младшем значащем бите слова 0:
typedef unsigned char block_t;
const unsigned block_bits=8;
inline void set_bit(block_t *d,unsigned i) {
unsigned b=i/block_bits;
unsigned bit=i-(block_bits*b); // same as i%b
block_t &bl=d[b];
bl|=(1<<bit); // or bit with 1 (others anded w/ 0)
}
inline void clear_bit(block_t *d,unsigned i) {
unsigned b=i/block_bits;
unsigned bit=i-(block_bits*b); // same as i%b
block_t &bl=d[b];
bl&=(~(1<<bit)); // and bit with 0 (other bits anded w/ 1)
}
inline void modify_bit(block_t *d,unsigned i,bool val) {
if (val) set_bit(d,i) else clear_bit(d,i);
}
inline bool get_bit(block_t const* d,unsigned i) {
unsigned b=i/block_bits;
unsigned bit=i-(block_bits*b); // same as i%b
return d[b]&(1<<bit);
}
Очевидно, что если правило для битовой организации отличается, вам придется изменить вышеприведенное.
Эффективно использовать максимально широкий процесс ЦП, так как block_t лучше всего (не забывайте менять block_bits
), если только не работает порядок байтов с библиотекой, которую вы используете.
Другие советы
Я думаю, что достаточно нескольких макросов:
#define set_bit0(buf, i) ((buf)[(i)/8]&=~(1u<<(i)%8))
#define set_bit1(buf, i) ((buf)[(i)/8]|=1<<(i)%8)
#define get_bit(buf, i) ((buf)[(i)/8]>>(i)%8&1)
Кроме того, обмен порядком байтов может быть выполнен быстрее. Например, для 64-разрядного целого числа v следующие операции меняют свой порядок байтов:
v = ((v & 0x00000000FFFFFFFFLLU) << 32) | (v >> 32);
v = ((v & 0x0000FFFF0000FFFFLLU) << 16) | ((v & 0xFFFF0000FFFF0000LLU) >> 16);
v = ((v & 0x00FF00FF00FF00FFLLU) << 8) | ((v & 0xFF00FF00FF00FF00LLU) >> 8);