追加する構文砂糖に関係なく、マスキングとシフトが起こります。使い方を簡単にしたいが、最初に行うのが少し難しい場合は、クラスを使用して、マクロ/テンプレートコードを少し使って、新しいクラスを少し簡単に定義できるようにする:
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();
あなたのフィールドは、バッキングフィールドの範囲の外にある場合は、コンパイル時に主張し得るでしょう。フィールドが重複していないかどうかはチェックされていないので、そのことに注意する必要があります。
ビットフィールドを使用するのは魅力的ですが、移植性がありません。これはしばしばデングブレイカーになる可能性があります。私が探しているのは –
ですが、ブライアンは移植性がなく、私のOSで動作しませんでしたが、 –