位域的二进制"bulk"序列化

Binary "bulk" serialization of bitfields

本文关键字:bulk 序列化 二进制 位域      更新时间:2023-10-16

我有很多布尔属性的对象,所以我使用位域来打包更紧凑的属性。我还希望能够以一种紧凑的方式序列化和反序列化这些属性,例如,不是逐个字段,而是通过序列化和反序列化保存字段的64位单元。这种方式不仅更快(例如,避免所有的移动和东西),而且内存效率提高了8倍。

然而,我读到这个标准并不能保证位场的实现在不同的平台上是统一的。我能期望位域容器的"批量"二进制序列化在不同平台上产生统一的结果吗?或者,在处理属性时,手动移动和屏蔽会更安全,以便可以进行批量序列化和反序列化?

您可以查看std::bitset:

它提供了定义良好的函数来将您的位转换为unsigned long类型,并从存储的unsigned long类型创建bitset类型。定义bitset的第一个位是ullong表示的最低有效数字。

所以你可以这样写:

 std::bitset<N> bits;
 unsigned long long val = bits.to_ullong();
 // serialize your ullong value
 // load ullong from serialized data
 unsigned long long val2 = ...;
 std::bitset<N> newBits(val2);

所以,只要你的序列化可以正确加载/存储unsigned long long,你就可以开始了。

唯一的问题是当你有一个位域太大的unsigned long long。在这种情况下,标准没有提供提取位域的简单方法。

一种可能性是使用ASN.1通过BIT STRING来处理此问题。它以一种独立于本地表示的方式精确地定义序列化。这使得它可以跨平台保持一致,而不管本地平台是大端还是小端。您可以在http://asn1-playground.oss.com上使用免费的在线ASN.1编译器和编码器/解码器来查看结果序列化。

ASN。

平台端序的差异表明任何这样的序列化都是不可移植的。基于此,我想说,你不能指望位域容器的批量二进制序列化在不同平台上是统一的。

解决方案必须考虑位的顺序并根据平台进行校正。

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

(所有示例见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);
    }
};