12

私はネットワーク データ ストリームの解析に取り組んでいます。データ ストリームをデータ構造に直接マップする方法があるかどうか疑問に思っています。

たとえば、RTP プロトコルのデータ構造を次のように定義したいと考えています。

class RTPHeader
{
   int version:2; // The first two bits is version.
   int P:1;  // The next bits is an field P.
   int X:1;
   int CC:4;
   int M:1;
   int PT:7;
   int sequenceNumber;
   int64 timestamp;
   .....
};

で、こんな使い方。

RTPHeader header;
memcpy(&header, steamData, sizeof(header));

しかし、C++ コンパイラはメンバー間にパディングを挿入するため、メンバー (ビット フィールド メンバーを含む) 間にパディングが追加されないように制御する方法はありますか?

私の例ではビットフィールドが存在する可能性があるため、この質問は構造体のデータメンバー間のパディングバイトを取り除く方法の複製ではありません。

4

3 に答える 3

8

alignofC++11 を使用できる場合は、オペレーターで実装された align コントロールを利用できます。

C++11 コンパイラを使用できない場合、役立つ非標準の代替手段があります。GCC では__attribute__(packed)、MSVC では#pragma pack.

選択したものが GCC バリアントの場合、属性は構造体の最後に配置する必要があります。

class RTPHeader
{
    int version:2; // The first two bits is version.
    int P:1;  // The next bits is an field P.
    int X:1;
    int CC:4;
    int M:1;
    int PT:7;
    int sequenceNumber;
    int64 timestamp;
    .....
} __attribute__((packed)) ; // attribute here!

MSVC を選択した場合は、構造体の前にプラグマを配置する必要があります。

#pragma pack(1) // pragma here!
class RTPHeader
{
    int version:2; // The first two bits is version.
    int P:1;  // The next bits is an field P.
    int X:1;
    int CC:4;
    int M:1;
    int PT:7;
    int sequenceNumber;
    int64 timestamp;
    .....
};

コードを両方でコンパイルする必要がある場合、(C++11alignof演算子を使用しない) 唯一の方法は条件付きコンパイルです。

#ifdef MSVC
#pragma pack(1)
#endif
class RTPHeader
{
    int version:2; // The first two bits is version.
    int P:1;  // The next bits is an field P.
    int X:1;
    int CC:4;
    int M:1;
    int PT:7;
    int sequenceNumber;
    int64 timestamp;
    .....
#ifdef GCC
}__attribute__((packed));
#else
};
#endif
于 2013-09-06T09:20:26.990 に答える
3

このコードが任意のマシンで「機能する」という要件がない限り、たとえば、どのバイト境界int(通常は 4 バイト境界) に制限があるマシンなど、

 #pragma(pack)

動作するはずであり、GCCだけでなく、Microsoft および「Microsoft プラグイン互換」コンパイラ (Intel のコンパイラなど) でもサポートされています。

ただし、アラインされていないアクセスはすべてのプロセッサでサポートされているわけではないことに注意してください。そのため、16 ビット値でブロックを開始し、その後に 32 ビット値が続くと、int問題が発生する可能性があります。

また、シーケンス番号にサイズの整数を使用して、すべてのコンパイラで 32 ビットであることを確認し、突然 16 ビットまたは 64 ビットにならないようにします。

また、C++ 標準は、ビットがビットフィールドに格納される順序について何も述べていないことにも注意してください。ビットフィールドはバイト順 (リトル エンディアン マシンは最初に最下位ビットから開始し、ビッグ エンディアン マシンは最初に最上位ビットから開始します) に従って格納されることを期待できますが、標準ではその点について何も述べられていません。

于 2013-09-06T09:12:46.513 に答える