2017-10-31 3 views
0

ソケットCを介して送信されたとき、私は次のようなビットフィールドがあります。ビットフィールド値の変更++

typedef struct __attribute__((__packed__)) MyStruct { 
    unsigned int val1:14; 
    unsigned int val2:1; 
    unsigned int val3:1; 
    unsigned int val4:1; 
    unsigned int val5:1; 
    unsigned short aFullShort; 
    unsigned int aFullInt; 
} MyStruct; 

私は、ネットワークを介してこれらの値を送信していますし、時には送信者がval1が(設定されていると思いますことに気づいたが送信前に値を印刷することによって検証可能ですが、受信者はval1が設定されていることを認識しません)。次のように送信するためのコードは次のとおり

MyStruct* myStruct = new MyStruct(); //initialize fields here 
sendto(sock, myStruct, sizeof(MyStruct), 0, ...); 

読み取りのためのコードは次の通りである:

unsigned char theBuffer[sizeof(MyStruct)]; 
recvfrom(aSocket, &theBuffer, sizeof(theBuffer), 0, ...); 

ソケットからバイトを読み取った後、私はMyStructにバイトキャスト再解釈とエンディアン行いますaFullShortおよびaFullIntの変換。送信者がそれを1に設定したときに受信者がval1が0であると受信者が判断するように破損が発生します。なぜこれが起こりますか?コンパイラが送信側と受信側の異なるパディングを挿入している可能性がありますか?単一のビット値のエンディアンを心配する必要がありますか?

+1

送信者/受信者はOSと全く同じコンパイラです。ビットフィールドレイアウトは実装定義です。 –

+0

@RichardCritten送信者と受信者は同じホストで実行され、同じコンパイラを使用してコンパイルされます。 2つの別個のバイナリが送信者と受信者に対して作成されます。これにより、コンパイラは2つのターゲットに対して異なる最適化を行うことができます。 – user1832287

+0

送信者の '(char *)(void *)myStruct'と受信者の' theBuffer'のダンプをダンプします。バイトは同じですか?そうであれば、構造のレイアウトの違いを指し示します。 – ikegami

答えて

2

コンパイラは、ビットフィールドを必要に応じてレイアウトできます。それは、実行するたびにランダム化することができます。これを禁止するルールはまったくありません。信頼できる予測可能なバイナリ形式でデータをシリアル化する場合は、それを行うコードを記述します。

唯一の例外は、コンパイルにパックされた構造体の保証がいくつかあり、自分自身をそのコンパイラのみに限定したい場合です。あなたは使用しているコンパイラを指定していませんが、それはそうではないかと思います。

このようなコードを書く理由はありません。関連する標準で動作することが保証されているコードを作成したいと考えています。何も起こりません。

+0

ビットフィールドレイアウトは実装固有のものですが、一貫していなければなりません。ファイルにビットフィールドを書き込み、後で同じ実装でファイルを読み込む場合は、同じ値を返す必要があります。ランダムであることはできません。 – Barmar

+0

@Barmarなぜそれを言うのですか?私はあなたがそれが一貫して起こると期待する理由を理解しています。しかし、あなたはそれが「一貫していなければならない」と思いますか? C++標準ではそう言いますか? POSIXはありますか?あなたのコンパイラのドキュメントですか? –

+0

でなければ、別々のコンパイルユニット内の何か間の通信にビットフィールドを使用できないためです。ライブラリなどの引数には使用できませんでした。 – Barmar

関連する問題