如何将位集转换为字节数组/uint8数组?

10

我需要从位集中提取字节,其中可能(不)包含多个CHAR_BIT位。我知道需要将位集中多少位放入数组中。例如,

位设置为std :: bitset <40> id;

有一个单独的变量nBits,表示id中可用的位数。现在我想以CHAR_BIT的倍数提取这些位。我还需要注意nBits%CHAR_BIT!= 0 的情况。 我可以将其放入uint8数组中。


2
如果你的位数小于sizeof(unsigned long),那么使用bitset::to_ulong就很简单了。但现在看来,我认为没有简单的解决方案。std::bitset没有像std::vector那样的data()函数(尽管gcc版本有一个未经记录和试验的_M_getdata函数,就是它...)。由于没有其他东西,你只能单独访问每个位。或者序列化成字符串或通过流,但这些方法都不是特别有效率的。 - Damon
3个回答

21
你可以使用boost::dynamic_bitset,它可以通过boost::to_block_range转换为一系列“块”。
#include <cstdlib>
#include <cstdint>
#include <iterator>
#include <vector>
#include <boost/dynamic_bitset.hpp>

int main()
{
    typedef uint8_t Block; // Make the block size one byte
    typedef boost::dynamic_bitset<Block> Bitset;

    Bitset bitset(40); // 40 bits

    // Assign random bits
    for (int i=0; i<40; ++i)
    {
        bitset[i] = std::rand() % 2;
    }

    // Copy bytes to buffer
    std::vector<Block> bytes;
    boost::to_block_range(bitset, std::back_inserter(bytes));
}

需要注意的一个问题是,向量的内部类型需要与用于构造位集的块类型匹配(在本例中为unsigned char)。如果位集具有4字节块但向量具有1字节块,则to_block将悄悄地截断每个块的后3个字节。因此,在Emile的答案中更改向量声明为std::vector<Bitset::Block> bytes会更加安全。 - prideout
更正我的评论:内部类型是 Bitset::block_type,而不是 Bitset::Block - prideout
@prideout:添加了“Block”typedef以避免您所描述的情况。 - Emile Cormier

3

很不幸,在语言内部没有好方法,假设你需要的比 unsigned long 中的位数更多(在这种情况下,可以使用 to_ulong)。您将不得不遍历所有位并自己生成字节数组。


3

使用标准C++11,您可以通过移位和掩码操作从40位的bitset中获取字节。我没有处理除8和40以外的不同值以及第二个数字不是第一个数字的倍数的情况。

#include <bitset>
#include <iostream>
#include <cstdint>

int main() {
    constexpr int numBits = 40;

    std::bitset<numBits> foo(0x1234567890);
    std::bitset<numBits> mask(0xff);

    for (int i = 0; i < numBits / 8; ++i) {
        auto byte =
            static_cast<uint8_t>(((foo >> (8 * i)) & mask).to_ulong());
        std::cout << std::hex << setfill('0') << setw(2) << static_cast<int>(byte) << std::endl;
    }
}

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