2009-03-17 33 views
1

ビットフィールドの設定と操作の両方について不思議です。C++のビット配列のフィールドの操作

私は既にC/C++ Code to treat a character array as a bitstreamを見つけましたが、それは私の疑問と似ていますが、それは私が考えている素晴らしいアプローチを与えてくれません。

私はstlのビットセットを考えていましたが、データセットは1,2,3,4,7,8,16ビットフォーマットのビットレイアウトと非常に複雑です。

データ内の項目にアクセスしたいとします.4番目のフィールドは、バイト境界をまたいだコードの8ビット部分ですが、これを行う簡単な方法はありますか?私は4のデータにアクセスしたり、4にデータを設定することをおSTLの実装を探しています

byte 1 byte 2 
11112344 44444455 

、私は単一バイトにデータをシフトする必要が愚かなようだと、何かが、このために存在すると仮定し、それを隠す。それを書くことも難しいようで、そのような仕事を達成するためのより簡単な方法があるはずです。

別の方法がありますか?

編集 - 正規ビットフィールドが不足している理由は、私のデータセットは、長さが約20バイトであると私はビット順

答えて

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; 

は何をしたいですか?

オンザフライで異なるレイアウトをプログラムで構築できるようにしたいですか?

+0

ビットフィールドを使用するのは魅力的ですが、移植性がありません。これはしばしばデングブレイカーになる可能性があります。私が探しているのは –

+0

ですが、ブライアンは移植性がなく、私のOSで動作しませんでしたが、 –

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(); 

あなたのフィールドは、バッキングフィールドの範囲の外にある場合は、コンパイル時に主張し得るでしょう。フィールドが重複していないかどうかはチェックされていないので、そのことに注意する必要があります。

+0

は216ビットで動作しますか?それは16ビットの解決策のようです –

+0

あなたは最大のフィールドのために64ビットで立ち往生します。 – Eclipse

+0

「ロングショート」って何?列挙型の定数値を定義していませんか? –

0

vector<bool>Boost.DynamicBitsetなどの既存のクラスは、あなたのために何もしません。

基本的な実装では、シフトとマスキングを行う必要がありますが、それについては何も愚かではありません。独自のクラスの書き方やテンプレートvector<bool>またはvector<something_else>が、その難しいことではありませんし、その後、あなたのような、あなたの要件が何であるかをあなたが考えるためのコードをマスキング/シフトを最適化するために取得する基礎となる使用:

  • され、このランダムアクセスをかシーケンシャル? (シーケンシャルな場合は、シフトしたマスクの再計算を避けることができます。)
  • すべての要素は同じサイズですか、任意のビットオフセットで任意の要素をインデックスしていますか?