2011-12-05 7 views
3

私のゲーム用のデータパッカーを作成しています。アイデアは、属性をパックし、ネットワーク上やデータパッキングが望ましい他の領域にデータを流すことができるものを書くことです。私はhttp://cplusplus.com/articles/zb07M4Gy/のバージョンを使って私の目標の一部を達成しました。私のコードは次のようになります:C++で移動せずにユニオンからビットにアクセスする

namespace detail 
{ 
    // Determine whether _Type is signed or unsigned. 
    // _Result is then either a signed or unsigned char 
    template < typename _Type > 
    struct sign 
    { 
     typedef typename std::_If< std::tr1::is_unsigned<_Type>::value, unsigned char, signed char >::_Type _Result; 
    }; 
} 

// Template for packing and unpacking data 
// at bit and byte level 
template < typename _Type > 
struct packer 
{ 
    typedef typename _Type value_type; 

    static const int num_bytes = sizeof(value_type); 
    static const int num_bits = num_bytes * CHAR_BIT; 

    union 
    { 
     value_type packed_value; 
     typename detail::sign<value_type>::_Result byte[num_bytes]; 
    }; 
}; 

ビットシフトなしで個々のビットへのアクセスを許可するにはどうすればよいですか?私はstd :: bitsetを使うことはできません。なぜなら、それは普通のコンストラクタを持っていて、boolの配列はビットの代わりに各エントリにバイトを割り当てる結果になるからです。

理想的には、ビット設定/マクロのチェックを避けたいと思います(ただし、私の手は縛られているようですが)。移植性とエンディアンの問題がありますが、それを除いて、私の目標を達成する方法はありますか?再帰的に配列を建設する

template< int _NumBits > 
struct bit_field 
{ 
    bit_field< _NumBits - 1 > the_other_bits; 

    int value : 1; 

    int operator[](const int in_index) 
    { 
     return reinterpret_cast< int* >(this)[index]; 
    } 
}; 

template< > 
struct bit_field<0> 
{ 
    int value : 1; 

    int operator[](const int in_index) 
    { 
     return reinterpret_cast< int* >(this)[index]; 
    } 
}; 

私が持っていたアイデアのようなものを使用することでした。しかし、この構造体の問題は整列です。この構造体はMSVC10の4バイトでパッカー構造体に132バイトの合計を与えます。これは4バイトの整数で作業する場合には理想的ではありません...

提案(「マン・アップ・ビットシフト」を含む...)は大歓迎です。

答えて

3

あなたはビットフィールドを使用することができます。

struct byte 
{ 
    bool bit0 : 1; 
    bool bit1 : 1; 
    bool bit2 : 1; 
    bool bit3 : 1; 
    bool bit4 : 1; 
    bool bit5 : 1; 
    bool bit6 : 1; 
    bool bit7 : 1; 
}; 

とカスタム梱包して、あなたの組合で

union something 
{ 
    byte bytes[num_of_bytes]; 

}; 
+0

+1「ビットシフトを使用しない」ソリューションを提供するため。 –

+0

私はこの道を下ることを非常に誘惑しています。私は、8ビット以外の数字であるシステムで作業するつもりはないと確信しているので、8ビットバイトが安全であると仮定します。また、ビットシフトを使用しない答えを提供するために1つプラス。 – BigDaveDev

0

あなたがチェックしたい属性のビット位置に関連した定数の束定義することができます。

const UINT8 BITPOS_ATT_ISMALE = 1; 
const UINT8 BITPOS_ATT_ISCUST = 2; 
const UINT8 BITPOS_ATT_NOCALL = 4; 
const UINT8 BITPOS_ATT_NOSMS = 8; //and so on for 16, 32, 64, however many you need 

をして、あなただけのビット単位を使用して、属性かどうかを判断するためにシフトする必要はありません設定されています。

EG:

bool isAttSet(UINT8 attributeToCheck, UINT8 attributeSet) 
{ 
    return (attributeToCheck & attributeSet); 
} 

入力BITPOS_ATT_ISCUST BITPOS_ATT_ISMALE、BITPOS_ATT_NOCALL、およびBITPOS_ATT_NOSMSのための真のではなく、01001101を返します。

EDIT:「packed_value」を渡すことになり、テンプレートクラスに応じて属性のサイズを一致させる必要があります。

+0

ismaleとiscustの両方を意味しない限り、BITPOS_ATT_NOCALLは0x04でなければなりません。 –

+0

4進数= 0x4 16進数?最初の編集の前に私を捕まえましたか?誤って0x03分であった。 – Dennis

+1

あなたが編集する前にコメントしました。 –

1

ビットシフトを使用して脳の痛みから何時間もあなたの将来を守ってください。

具体的には、このレベルのビットパッキングを実行するときに、より高いレベルで抽象化し、コンパイラが期待することを信頼する必要はありません。ネットワーク上のデータのビットサイズ、順序、レイアウト、および特定のプラットフォームに格納されている順序を明示して文書化する必要があります。そして、ストレージがプロセッサの種類によって異なることに対処するために、プラットフォーム固有のセクションが必要になります。ビットレベルの構造に気づかないクライアントコードを書くことはできますが、データのパッキングコードはできるだけ明示的にする必要があります。

+0

ビットシフトを中心にして言語全体が設計されているわけではありませんか? * g * – hochl

1

、あなたが順番にパックされたデータであるデータの種類を事前に知っておく必要があり開梱それを開梱する。つまり、データを使用しているパーツと、データをパッキングしてアンパックするパーツとの間に多くの結合があります。

私はアトリビュートを追加しました。これを考慮に入れてパッカー/アンパッカーを変更しましょう。それは吸うとそれはあなたに多くのスペースを節約しません。

送信するデータの量が本当に心配な場合は、lzoやgzipのような圧縮を使用してください。

このように、それぞれのデータ型を2つ表現する必要はありません。圧縮せずに送信/受信コードをデバッグし、プログラムの残りの部分を知らせずに圧縮/伸長を追加することができます。

質問については、まだ梱包を行う予定の場合: ビットシフトを先に使用してください。ある時点で、それがひどいと間違っていると感じたら... 少なくとも、より一般的な方法を見つけるための実例ベースがあります。

一般的な方法を書くことは、通常、力強いやり方が間違っていることを意味します。よりシンプルでアドホックな方法から始めるということは、最終的に何か新しいものが必要になったときに、その問題の経験があることを意味します。

+0

私は比較的短い時間でプログラマとして多くのビットシフトコードを書いています。私の希望は、上記の構造をより多くの機能を完成させることだけでした。あなたは私のアプローチがパッキングの最初の試みのために残忍であることは間違いありませんが、私が言いましたように、ここでの最初の試みではありません;-) – BigDaveDev

関連する問題