Как читать и записывать биты в байтовый массив

StackOverflow https://stackoverflow.com/questions/1415755

  •  06-07-2019
  •  | 
  •  

Вопрос

У меня есть 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);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top