一部のコンパイラには、構造体のパッキング指定子があります。たとえば、::
RealView ARMコンパイラには「__packed」があります。 Gnu Cコンパイラには「__attribute__((__packed__))」があります。 「#pragma pack(1)」 のみがあります。
struct定義に入れることができるものが必要です。
情報/ハック/提案? TIA ...
洗練された方法はわかりませんが、次のような恐ろしいことができます。
#include "packed.h"
struct Foo { /* members go here */ } PACKED;
#include "endpacked.h"
MSVCの場合、packed.h:
#define PACKED
#pragma pack(Push,1)
endpacked.h
#pragma pack(pop)
#undef PACKED
Gccの場合、packed.h:
#define PACKED __attribute__ ((__packed__))
endpacked.h:
#undef PACKED
基本的に、パッキングはプラットフォームに依存しすぎています。パックされた構造体に8ビットのフィールドがあり、16ビットのバイトを持つシステムを考えてみましょう。パックするだけでデータを表す構造体を持つことはできません。2つのシステム間で転送されるときに、8ビットバイトが16ビットバイトに変換される方法を知っている必要があります。 16ビットマシンの構造体にはビットフィールドが必要な場合があります。その場合、実装でどのようにレイアウトされるかを知る必要があります。
そのため、コードを一般的に移植可能にすることを目的としている場合、必要なパック構造をヘッダーファイルのプラットフォーム固有のセクションで定義する必要があります。むしろ、将来の移植が必要に応じてできるようにコードを構成します。
GNU gccに対してPACKをこのように定義できます
#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
visual C++の場合は次のようになります。
#define PACK( __Declaration__ ) __pragma( pack(Push, 1) ) __Declaration__ __pragma( pack(pop) )
そして、次のように使用します。
PACK(
struct myStruct
{
int a;
int b;
});
私はこの質問が今では古いことを知っていますが、以前に投稿されたものよりも良い解決策があると思います。結局、構造体宣言行のMSVCケースにプラグマを入れることができます。以下を考慮してください。
#ifdef _MSC_VER
# define PACKED_STRUCT(name) \
__pragma(pack(Push, 1)) struct name __pragma(pack(pop))
#Elif defined(__GNUC__)
# define PACKED_STRUCT(name) struct __attribute__((packed)) name
#endif
次に、これは次のように使用できます:
typedef PACKED_STRUCT() { short a; int b } my_struct_t;
PACKED_SRUCT(my_other_struct) { short a; int b };
等.
ここで重要なのは、__ pragmaの使用は、構造体の宣言行の周りでのみ必要なことです。構造体名が指定されている場合はこれを含める必要があります。したがって、名前はマクロのパラメーターになります。もちろん、これは列挙型/クラスに拡張するのは簡単です。これは読者への演習として残しておきます!
パックドキュメントのMSDNページ にあるテストプログラムは、これを確認するのに役立ちます。
[〜#〜] edit [〜#〜]
私のテストでは、WindowsでIntelコンパイラを使用していたことがわかりました。 icl.exeを使用すると、このアプローチは問題なく機能しますが、Microsoftコンパイラー(cl.exe)では機能しません(2010および2013でテスト済み)。
GCCはVC++パック関連のプラグマをサポートしているため、逆の方法でも実行できます。詳細については、 こちら をご覧ください。
エキス...
Microsoft Windowsコンパイラとの互換性のために、GCCは_
#pragma
_ディレクティブのセットをサポートします。これらのディレクティブは、構造体(ゼロ幅ビットフィールド以外)、ユニオン、およびその後に定義されるクラスのメンバーの最大アライメントを変更します。以下のn値は常に2のべき乗である必要があり、バイト単位で新しいアライメントを指定します。
#pragma pack(n)
は、単に新しい配置を設定するだけです。
#pragma pack()
は、コンパイルを開始したときに有効だったアライメントにアライメントを設定します(コマンドラインオプション_-fpack-struct[=<n>]
_もコード生成オプションを参照)。
#pragma pack(Push[,n])
は、内部スタックに現在のアライメント設定をプッシュし、オプションで新しいアライメントを設定します。
#pragma pack(pop)
は、内部スタックの最上部に保存されているものにアライメント設定を復元します(そしてそのスタックエントリを削除します)。
#pragma pack([n])
はこの内部スタックに影響しないことに注意してください。したがって、#pragma pack(Push)
の後に複数の#pragma pack(n)
インスタンスが続き、単一の#pragma pack(pop)
でファイナライズされる可能性があります。いくつかのターゲット、例えばi386およびpowerpcは、文書化された
__attribute__((ms_struct))
として構造をレイアウトする_ms_struct
_ _#pragma
_をサポートします。_
#pragma ms_struct on
_は、宣言された構造のレイアウトをオンにします。_
#pragma ms_struct off
_は、宣言された構造のレイアウトをオフにします。_
#pragma ms_struct reset
_はデフォルトのレイアウトに戻ります。
サポートするコンパイラに応じて、別の解決策は、少なくともバージョン4.0.4以降、GCCがMicrosoftスタイルのパッキングプラグマをサポートしていることに注意することです(バージョン3.4.6および4.0.4のオンラインドキュメントはgnu.orgで入手できます) -プラグマは前者には記述されておらず、後者にあります)。これにより、構造定義の前に#pragma pack(Push,1)
を使用し、定義の後に#pragma pack(pop)
を使用するだけで、どちらでもコンパイルできます。
構造体に入れるために何かが必要なのはなぜですか?
#pragma pack(1)
は同じだと思うか、何か不足していますか?
あなたはこれを行うことができます:
struct Foo
{
#pragma pack(Push, 1)
int Bar;
#pragma pack(pop)
};
しかし、見苦しい。