0

私はこのような構造体を持っています:

typedef struct _HEADER_IO
    {
        uint8_t field1 : 2;
        uint8_t field2 : 4;
        uint8_t field3 : 1;
        uint8_t field4 : 1;
        uint16_t field5;
        uint8_t field6;
    } HEADER_IO;

これは基本的に、tcpを介して送信されるメッセージヘッダーです。サーバーはこれを読み取って、バッファー内でどのデータが続くかを認識します。ただし、何らかの理由でサイズが4バイト(2 + 4 + 1 +1の最初のバイト+フィールド5から2バイト+1バイトのフィールド6)であるのではなく、サイズは6バイトです。

メモリビューで検索すると、次のようになります。

XX AA XX XX XX AA

それ以外の:

XX XX XX XX

私が何をしてもAAが設定されない場所。これは、ヘッダーをサーバーに送信することを計画してsend()いて、サーバーがヘッダーを誤って解釈するように余分なバイトが含まれているため、問題になります。私は何が間違っているのですか?

4

2 に答える 2

1

一般に、このようなものにビットフィールドを使用することはお勧めできません。ビットがどのバイトになるかを事前に正確に知ることができないため、およびパディングとアラインメントの問題があるため。

私の意見では、C構造体が提供するものよりも外部表現をより細かく制御する必要があるという事実に「専念」し、手動で行う方がよいと思います。もちろん、構造体をメモリ内(内部)表現として保持することもできます。

基本的に、次のような関数を記述します。

size_t header_serialize(unsigned char *buf, size_t max, const HEADER_IO *header);

その仕事は、のメモリ内でbuf、を表す適切なバイトシーケンスを構築することheaderです。

(コメントに基づいて)明確にするために、目的は、からフィールドを読み取ることheaderです。

memcpy(buf, header, sizeof *header);  /* DON'T DO THIS! */

代わりに、のフィールドから、期待される外部表現をバイトごとにアセンブルすることになっていますheader。そうすれば、コンパイラがメモリ内の形式に対して何をするかに関係なく、常に同じ外部表現を取得できますheader

于 2012-04-19T13:18:40.943 に答える
0

標準Cでは、構造体メンバーの間にパディングを挿入できるという事実を助けることはできません。処理する前に、データをデコードして構造体に格納する関数を作成する必要があります。これは、一部のアーキテクチャでは、アラインされていないメモリアクセス(たとえば、4バイトにアラインされていないポインタからの読み取り)は非常にコストがかかり、コストを回避するためにCが構造を自動的にパディングするためです。この機能をオンまたはオフにする標準的な方法はありません。

たとえば、GCC__attribute__((packed))では、構造体定義の後に追加できます。VisualStudioには、GCCでもサポートされている#pragmaコマンド(http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.htmlを参照)がありますが、全体としてはこれに注意してください。非標準です。

あなたのコメントはそれがWindowsプログラムであると述べたので、構造体定義の前にこれを追加すればおそらくそれはうまくいくでしょう:

#pragma pack(push,1)

そしてこれはその後:

#pragma pack(pop)

ヘッダーをより手動でデコードするコードを作成する方が移植性が高くなりますが、上記のアプローチの方が高速です。

于 2012-04-19T13:01:09.710 に答える