将字节数组转换为位集

10
我有一个由随机数生成器生成的字节数组,我想将其放入STL位集中。
不幸的是,Bitset只支持以下构造函数:
1. 一个由1和0组成的字符串,如“10101011”。 2. 一个无符号长整型。(我的字节数组会更长)
现在我能想到的唯一解决方案是逐位读取字节数组并制作一个由1和0组成的字符串。有没有更高效的解决方案?
6个回答

11

像这样的吗?

#include <bitset>
#include <climits>

template<size_t numBytes>
std::bitset<numBytes * CHAR_BIT> bytesToBitset(uint8_t *data)
{
    std::bitset<numBytes * CHAR_BIT> b;

    for(int i = 0; i < numBytes; ++i)
    {
        uint8_t cur = data[i];
        int offset = i * CHAR_BIT;

        for(int bit = 0; bit < CHAR_BIT; ++bit)
        {
            b[offset] = cur & 1;
            ++offset;   // Move to next bit in b
            cur >>= 1;  // Move to next bit in array
        }
    }

    return b;
}

还有一个使用示例:

int main()
{
    std::array<uint8_t, 4> bytes = { 0xDE, 0xAD, 0xBE, 0xEF };
    auto bits = bytesToBitset<bytes.size()>(bytes.data());
    std::cout << bits << std::endl;
}

一次设置CHAR_BIT位比逐位设置更快且更容易 http://coliru.stacked-crooked.com/a/2ada0153b6d6baf0 - Mooing Duck

3

我花了很多时间编写一个反转函数(bitset -> 字节/字符数组)。以下是代码:

    bitset<SIZE> data = ...

    // bitset to char array
    char current = 0;
    int offset = 0;
    for (int i = 0; i < SIZE; ++i) {
        if (data[i]) { // if bit is true
            current |= (char)(int)pow(2, i - offset * CHAR_BIT); // set that bit to true in current masked value
        } // otherwise let it to be false
        if ((i + 1) % CHAR_BIT == 0) { // every 8 bits
            buf[offset++] = current; // save masked value to buffer & raise offset of buffer
            current = 0; // clear masked value
        }
    }
    
    // now we have the result in "buf" (final size of contents in buffer is "offset")

3
< p > bitset<>有第三个构造函数 - 它不带参数并将所有位设置为0。我认为你需要使用它,然后遍历数组,在字节数组中每个为1的位上调用set()

这可能有些暴力,但是它会起作用。将每个字节内的字节索引和位偏移转换为bitset索引会有一些复杂性,但是通过一点思考(也许在调试器下运行)解决问题并不难。我认为这比尝试将数组转换为字符串或流更简单,更有效。


2

这是我使用模板元编程实现的代码。

循环在编译时完成。

我采用了@strager的版本,并对其进行修改,以便为TMP做准备:

  • 更改了迭代顺序(以便我可以从中递归);
  • 减少了使用的变量数量。

在运行时中循环的修改版本:

template <size_t nOfBytes>
void bytesToBitsetRunTimeOptimized(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) {
  for(int i = nOfBytes - 1; i >= 0; --i) {
    for(int bit = 0; bit < CHAR_BIT; ++bit) {
      result[i * CHAR_BIT + bit] = ((arr[i] >> bit) & 1);
    }
  }
}

基于IT的TMP版本:
template<size_t nOfBytes, int I, int BIT> struct LoopOnBIT {
  static inline void bytesToBitset(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) {
    result[I * CHAR_BIT + BIT] = ((arr[I] >> BIT) & 1);
    LoopOnBIT<nOfBytes, I, BIT+1>::bytesToBitset(arr, result);
  }
};
// stop case for LoopOnBIT
template<size_t nOfBytes, int I> struct LoopOnBIT<nOfBytes, I, CHAR_BIT> {
  static inline void bytesToBitset(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) { }
};

template<size_t nOfBytes, int I> struct LoopOnI {
  static inline void bytesToBitset(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) {
    LoopOnBIT<nOfBytes, I, 0>::bytesToBitset(arr, result);
    LoopOnI<nOfBytes, I-1>::bytesToBitset(arr, result);
  }
};
// stop case for LoopOnI
template<size_t nOfBytes> struct LoopOnI<nOfBytes, -1> {
  static inline void bytesToBitset(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) { }
};

template <size_t nOfBytes>
void bytesToBitset(uint8_t* arr, std::bitset<nOfBytes * CHAR_BIT>& result) {
  LoopOnI<nOfBytes, nOfBytes - 1>::bytesToBitset(arr, result);
}

客户端代码:

uint8_t arr[]={0x6A};
  std::bitset<8> b; 
  bytesToBitset<1>(arr,b);

1

说实话,我有点无聊,开始思考是否有比逐个设置每个位稍微快一点的方法。

template<int numBytes>
std::bitset<numBytes * CHARBIT bytesToBitset(byte *data)
{
    std::bitset<numBytes * CHAR_BIT> b = *data;

    for(int i = 1; i < numBytes; ++i)
    {
        b <<= CHAR_BIT;  // Move to next bit in array
        b |= data[i];    // Set the lowest CHAR_BIT bits
    }

    return b;
}

这确实稍微快一些,至少在字节数组小于30个元素时是如此(取决于传递给编译器的优化标志)。如果数组比这更大,则通过移位位集所用的时间使得设置每个位更快。


0

你可以从流中初始化位集。我记不清如何将byte[]转换为流了,但是...

来自http://www.sgi.com/tech/stl/bitset.html

  bitset<12> x;

  cout << "Enter a 12-bit bitset in binary: " << flush;
  if (cin >> x) {
    cout << "x =        " << x << endl;
    cout << "As ulong:  " << x.to_ulong() << endl;
    cout << "And with mask: " << (x & mask) << endl;
    cout << "Or with mask:  " << (x | mask) << endl;
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接