所以我想知道设置和操作位域。
我已经找到了C/C++ Code to treat a character array as a bitstream,这与我的问题类似,但它并没有给我一个很好的stl方法,我认为必须存在。
我在考虑来自stl的位集,但我的数据集非常复杂,位格式为1,2,3,4,7,8,16位格式。
让我们说我想访问我的数据中的一个项目,第4个字段是一个跨越字节边界的8位代码段,是否有一种简单的方法可以做到这一点?
byte 1 byte 2 11112344 44444455
我正在寻找一个好的stl实现来访问4中的数据或者将数据设置为4,我假设存在一些东西,因为将数据转换为单个字节并将其屏蔽掉似乎很愚蠢。写它似乎也很困难,并且应该有一种更简单的方法来完成这样的任务。
还有其他办法吗?
编辑 - 我的数据集长度大约为20个字节,我希望按位顺序保留所有数据
答案 0 :(得分: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;
做你想做的事吗?
您是否希望能够以编程方式动态构建不同的布局?
答案 1 :(得分: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();
如果您的字段超出了支持字段的范围,您将获得编译时断言。没有检查字段是否重叠,因此您必须注意这一点。
答案 2 :(得分:0)
现有的类vector<bool>
或Boost.DynamicBitset
似乎不会为您做任何事情。
底层实现将不得不进行转换和屏蔽,对此没有任何愚蠢。使用基础vector<bool>
或vector<something_else>
编写自己的类或模板并不难,然后您可以根据您的需求优化移位/屏蔽代码,例如: