1

所以我想知道设置和操作位字段。

我已经找到了将字符数组视为比特流的 C/C++ 代码,这与我猜想的问题相似,但它并没有给我一个很好的 stl 方法,我认为它必须存在。

我正在考虑来自stl的位集,但我的数据集非常复杂,位布局为 1、2、3、4、7、8、16 位格式。

假设我想访问我的数据中的一个项目,第 4 个字段是跨越字节边界的 8 位代码段,有没有简单的方法可以做到这一点?

字节 1 字节 2
11112344 44444455

我正在寻找一个好的 stl 实现来访问 4 中的数据或设置 4 中的数据,我认为存在一些问题,因为必须将数据转换为单个字节并将其屏蔽似乎很愚蠢。编写它似乎也很困难,并且应该有一种更简单的方法来完成这样的任务。

还有其他方法吗?

编辑 - 我的数据集长度约为 20 个字节,我想按位顺序保留它

4

3 回答 3

1

你能解释一下为什么常规位域是不够的吗?换句话说,为什么不这样做:

    struct ComplexBitLayout {
      unsigned field1 :4;
      unsigned field2 :1;
      unsigned field3 :1;
      unsigned field4 :8;
      unsigned field5 :2;
   } __attribute__((__packed__)); // or your compiler's equivalent

   ComplexBitLayout cbl;

   cbl.field4 = x;

做你想做的事?

您是否希望能够以编程方式即时构建不同的布局或其他什么?

于 2009-03-17T20:01:51.510 回答
1

无论您添加任何语法糖,掩蔽和转换都会发生。如果您想让事情变得真正易于使用,但首先要制作起来有点困难,您可以使用一个类,以及一些宏/模板代码,以便更容易定义新类:

template<bool> struct CompileTimeAssert;
template<> struct CompileTimeAssert<true> { };

#define ASSERT(check) if (!check) throw exception("Assertion Failure" #check)

#define ADDBITVALUE(backingField, backingFieldType, fieldName, offset, size) \
    public: \
    static const unsigned int fieldName##Offset = offset; \
    static const backingFieldType fieldName##Mask = CalculateMask<offset, size, backingFieldType>::Value; \
    public: \
    void Set##fieldName(backingFieldType value) \
    {\
        ASSERT(("Value too large for field.", (value & (fieldName##Mask >> fieldName##Offset)) == value));\
        backingField |= value << fieldName##Offset;\
    }\
    backingFieldType Get##fieldName() const\
    {\
        return (backingField & fieldName##Mask) >> fieldName##Offset;\
    }\
    private:

#define ADDSPANNEDVALUE(backingField1, backingField1Type, backingField2, backingField2Type, fieldName, offset1, size1, offset2, size2)\
    ADDBITVALUE(backingField1, backingField1Type, fieldName##internal1, offset1, size1)\
    ADDBITVALUE(backingField2, backingField2Type, fieldName##internal2, offset2, size2)\
    public: \
    void Set##fieldName(backingField1Type value) \
    {\
        backingField1Type value1 = value << (sizeof(backingField1Type)*8-size1);\
        value1 = value1 >> (sizeof(backingField1Type)*8-size1);\
        Set##fieldName##internal1(value1);\
        Set##fieldName##internal2(value >> size1);\
    }\
    backingField1Type Get##fieldName() const\
    {\
        return Get##fieldName##internal1() | (Get##fieldName##internal2() << size1);\
    }\
    private:

template <unsigned int Offset, int Size, typename T>
struct CalculateMask
{
    CompileTimeAssert<(Size > 0)> Object;
    static const T Value = (T)((1 << Offset) | CalculateMask<Offset + 1, Size - 1, T>::Value);
};

template <unsigned int Offset, typename T>
struct CalculateMask<Offset, 0, T>
{
    CompileTimeAssert<(Offset <= sizeof(T) * 8)> Object;
    static const T Value = 0;
};

然后像这样定义你的类:

class BitGroup
{
    unsigned short Values;
    unsigned short Values2;
    ADDBITVALUE(Values, unsigned short, Field1, 0, 12);
    ADDSPANNEDVALUE(Values, unsigned short, Values2, unsigned short, Field2, 12, 4, 0, 2);
    ADDBITVALUE(Values2, unsigned short, Field3, 2, 14);
public:
    BitGroup() : Values(0), Values2(0) {}
};

用法:

BitGroup bg;
bg.SetField1(15);
cout << bg.GetField1();
bg.SetField2(63);
cout << bg.GetField1();

如果您的字段超出支持字段的范围,您将获得编译时断言。没有检查字段是否重叠,因此您必须注意这一点。

于 2009-03-17T20:12:04.667 回答
0

似乎现有的类,例如vector<bool>Boost.DynamicBitset不会为您做任何事情。

底层实现将不得不进行转换和屏蔽,这没什么好笑的。使用底层编写自己的类或模板vector<bool>并不vector<something_else>难,然后您就可以针对您认为的需求优化转换/屏蔽代码,例如:

  • 这是随机访问还是顺序访问?(如果它是连续的,那么您可以避免重新计算您的移位掩码。)
  • 所有元素的大小是否相同,或者您是否在任意位偏移处索引任意大小的元素?
于 2009-03-17T20:19:29.657 回答