なぜC++#pragma pack
で構造体が必要なのですか? typedef
特に、ネットワーク通信でこれらの構造を使用している場合。
4 に答える
#pragma pack
構造体のメンバーの配置を制御します。一般的なデフォルト設定は 8 で、最大 8 バイトの長さのメンバーがそのサイズの倍数のアドレスに配置されるようにします。たとえば、double または 64 ビットのポインター。位置合わせが正しくない double の読み取りまたは書き込みは非常にコストがかかる可能性があり、CPU キャッシュ ラインの境界にまたがる場合、通常は 3 倍遅くなります。この配置により、メンバー間にパディングと呼ばれる未使用のスペースが生じる可能性があります。
この種のアラインメントは、多くの場合、ネットワーク フレームには不適切です。パディングなしで密集する傾向があります #pragma pack(push, 1)
#pragma pack ディレクティブは、ディレクティブに続く宣言を持つ構造体のメンバーに対してのみ、現在の位置合わせ規則を変更します。構造体のアラインメントには直接影響しませんが、構造体のメンバーのアラインメントに影響を与えることで、アラインメント規則に従って構造体全体のアラインメントに影響を与える可能性があります
同じ設定の 2 つのシステムを相互に通信させる必要がある場合 (テストなど)、POD (プレーンな古いデータ) (ポインター、仮想テーブル、std::strings..) であれば、構造体を送信できます。 . 使用できません)。なのでパックは不要です。
システムが同じセットアップを持っていない (または不明な) 場合は、プロトコルでシリアル化されたデータを送信する必要があるため、パックされた構造は機能しません。有効なプロトコルが使用可能かどうかを確認するのが最も簡単です。
コンパイラは、構造体のフィールドとサブフィールドを「パディング」します。つまり、中間に何も保持されていないメモリの空白のチャンクでメモリ内に整理します。Hans Passant's answer が説明しているように、効率を高めるためにこれを行います。
コンパイラ/ターゲット/最適化の設定が異なると、異なるパディングが行われ、等しい「論理」構造体が異なるメモリ表現に変換される可能性があるため、2 つの通信マシンがそれらの間で構造体を渡すと、相互に理解できない可能性があります。
#pragma pack は、コンパイラのパディングの自由を制限する方法です。
#pragma pack(push, 1) は、コンパイラーにまったくパディングしないように命令します。異なるコードで定義された 2 つの同一の構造体に対してこれを行うと、メモリ内で同じように表現されます。次に、ポインターと sizeof() を使用して、プロトコルを介して 1 つのアプリケーションで構造体の内容を安全に送信し、反対側でそれを取得して、同じ構造体に直接書き込むことができます。これもポインターと sizeof() を使用します。