15

std::bitset有一种to_string()方法可以序列化为char基于1s 和0s 的字符串。char显然,这对位集中的每个位使用单个 8 位,使序列化表示比必要的长 8 倍。
我想以二进制表示形式存储位集以节省空间。to_ulong()仅当我的位集中少于 32 位时,该方法才有意义。我有数百个。
我不确定我想在对象(地址)本身上使用memcpy()/ std::copy(),因为它假设对象是 POD。

API 似乎没有为我可以从中获取地址的内部数组表示提供句柄。

我还想要从二进制表示中反序列化位集的选项。

我怎样才能做到这一点?

4

6 回答 6

9

这是一种可能的方法,基于一次std::vector<unsigned char>读/写一个位的显式创建...

template<size_t N>
std::vector<unsigned char> bitset_to_bytes(const std::bitset<N>& bs)
{
    std::vector<unsigned char> result((N + 7) >> 3);
    for (int j=0; j<int(N); j++)
        result[j>>3] |= (bs[j] << (j & 7));
    return result;
}

template<size_t N>
std::bitset<N> bitset_from_bytes(const std::vector<unsigned char>& buf)
{
    assert(buf.size() == ((N + 7) >> 3));
    std::bitset<N> result;
    for (int j=0; j<int(N); j++)
        result[j] = ((buf[j>>3] >> (j & 7)) & 1);
    return result;
}

请注意,要调用反序列化模板函数,必须在函数调用中指定位集bitset_from_bytes大小,例如N

std::bitset<N> bs1;
...
std::vector<unsigned char> buffer = bitset_to_bytes(bs1);
...
std::bitset<N> bs2 = bitset_from_bytes<N>(buffer);

如果您真的关心速度,那么一种会有所收获的解决方案是进行循环展开,以便一次完成一个字节的打包,但更好的是编写您自己的不隐藏内部的 bitset 实现二进制表示而不是使用std::bitset.

于 2011-09-18T19:41:54.070 回答
1

编辑:以下不按预期工作。显然,“二进制格式”实际上是指“二进制的 ASCII 表示”。


您应该能够将它们写入std::ostreamusing operator<<。它在这里说:

[Bitsets] 也可以直接从二进制格式的流中插入和提取。

于 2011-03-10T20:02:54.660 回答
1

为了完整起见,回答我自己的问题。

显然,没有简单可移植的方法来做到这一点。

为简单起见(虽然不是效率),我最终使用to_string,然后从字符串的所有 32 位块(以及其余部分*)创建连续的 32 位位集,并to_ulong在每个位上使用将位收集到二进制文件中缓冲。
这种方法将位旋转留给 STL 本身,尽管它可能不是最有效的方法。

* 请注意,由于std::bitset是在总位数上进行模板化的,因此余数位集需要使用一些简单的模板元编程算法。

于 2011-09-17T19:03:37.493 回答
1

正如 gamedev.net 上的人所建议的那样,可以尝试使用boost::dynamic_bitset,因为它允许访问 bitpacked 数据的内部表示。

于 2011-10-11T13:24:41.633 回答
0

除了转换为字符串并对字符串进行自己的序列化,将 8 个字符的块分组为单个序列化字节之外,我看不到其他明显的方法。

编辑:更好的是只迭代所有位operator[]并手动序列化它。

于 2011-03-09T20:02:23.003 回答
0

这可能会对您有所帮助,它是各种序列化类型的一个小例子。我添加了 bitset 和 raw bit 值,可以像下面这样使用。

(所有示例都在https://github.com/goblinhack/simple-c-plus-plus-serializer

class BitsetClass {
public:
    std::bitset<1> a;
    std::bitset<2> b;
    std::bitset<3> c;

    unsigned int d:1; // need c++20 for default initializers for bitfields
    unsigned int e:2;
    unsigned int f:3;
    BitsetClass(void) { d = 0; e = 0; f = 0; }

    friend std::ostream& operator<<(std::ostream &out,
                                    Bits<const class BitsetClass & > const m
    {
        out << bits(my.t.a);
        out << bits(my.t.b);
        out << bits(my.t.c);

        std::bitset<6> s(my.t.d | my.t.e << 1 | my.t.f << 3);
        out << bits(s);

        return (out);
    }

    friend std::istream& operator>>(std::istream &in,
                                    Bits<class BitsetClass &> my)
    {
        std::bitset<1> a;
        in >> bits(a);
        my.t.a = a;

        in >> bits(my.t.b);
        in >> bits(my.t.c);
        std::bitset<6> s;
        in >> bits(s);

        unsigned long raw_bits = static_cast<unsigned long>(s.to_ulong());
        my.t.d = raw_bits & 0b000001;
        my.t.e = (raw_bits & 0b000110) >> 1;
        my.t.f = (raw_bits & 0b111000) >> 3;

        return (in);
    }
};
于 2019-09-07T13:31:30.787 回答