2

我有一个无符号字符缓冲区,我想知道如何将有符号和无符号位写入和读取到这个字节缓冲区。

Source Engine中有一个名为bf_write的类,其中两个主要方法(由 WriteString、WriteChar、WriteLong 等使用)使用两个名为WriteUBitLongWriteSBitLong的函数。

提前致谢

4

2 回答 2

10

如果位数是编译时常量:

#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) 在 little endian (Intel/AMD) CPUs 上,这意味着 int 数组的字节占用的内存可能与 int 中的位顺序不一致。如果它是“第 0 位是 int 0 的 lsb,...第 32 位是 int 1 的 lsb,...”那么在小端序中这与“第 0 位是 char 0 的 lsb,...位32 是 char 4 ..." 的 lsb,在这种情况下,您可以将指向 int 数组的指针转换为指向 char 数组的指针

3)假设您的位集/向量中的本机字节顺序并不是库所需要的,那么您必须要么必须创建自己的具有他们想要的布局的布局,要么将副本转录到他们的布局中。

a) 如果一个字节内的位顺序不同,则一个 256 个条目的查找表给出位反转的字节将是有效的。你可以用一个小程序生成表格。

b) 从 little<->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);
}

显然,如果位组织规则不同,则必须更改上述内容。

最好使用最广泛的 int 您的 CPU 进程,因为 block_t 是最好的(不要忘记更改block_bits),除非您使用的库无法解决字节序问题。

于 2009-09-12T18:26:08.027 回答
1

我认为几个宏就足够了:

#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);
于 2009-09-12T22:36:02.587 回答