web-dev-qa-db-ja.com

GCCの#pragmapack(Push、n)/#pragma pack(pop)と__attribute __((__ packed __、aligned(n)))の違いは何ですか?

特にGCC(つまり、両方をGCCでコンパイルする)では、次の2つの動作の違いは何ですか?

struct foo1 {
    char a;
    int b;
} __attribute__((__packed__, aligned(n) ));

そして:

#pragma pack(Push, n)
struct foo2 {
    char a;
    int b;
};
#pragma pack(pop)

それら 異なる動作をするように見えます

foo1 f1;
foo2 f2;

int& i1 = f1.b; // ok
int& i2 = f2.b; // cannot bind packed field 'f2.foo2::b' to 'int&'

なぜ一方にエラーがあり、もう一方にはエラーがないのですか?少なくとも、メモリのレイアウトは同じですか?

11
Claudiu

使用しているGCCのバージョンはわかりませんが、適切なマニュアルを見つけることができます オンライン 。これらの点ではすべてかなり互換性がありますが、属性とプラグマの動作は、一度定義されると、互換性のためにバージョン間で通常維持されるためです。現在GCC4シリーズから入手可能な最新バージョンであるGCC4.9.3のマニュアルから具体的な引用を引用します。特に、 type attributes および structure-packing pragmas のセクションが関連しています。

GCCマニュアルには、_#pragma pack_とその友人について書かれています。

構造体(ゼロ幅ビットフィールドを除く)、共用体、および後で定義されるクラスのメンバー最大アラインメントを変更する#pragmaディレクティブ。

(強調が追加されました)。 __attribute__((packed))について:

構造体または共用体タイプの定義に付加されるこの属性は、必要なメモリを最小限に抑えるために、構造体または共用体の各メンバー(幅がゼロのビットフィールドを除く)を配置することを指定します。

__attribute__ ((aligned(n)))について:

この属性は、バイト単位で測定された指定されたタイプの変数最小アライメントを指定します。

(強調が追加されました)。

したがって、いいえ、Pushの有無にかかわらず、#pragma pack(n)は、一般に、__attribute__((packed, aligned(n))を構造体タイプにアタッチすることと同じ意味ではありません。前者は、影響を受ける構造体のメンバーをnバイト以下の境界に揃えることを指定します。後者は、影響を受ける構造のメンバーに最小許容パディングを詰めること、および構造全体のインスタンスに対して選択された配置要件がn以上でなければならないことを指定します。それらは同じではないだけでなく、あまり似ていません。

構造体の定義に影響を与える#pragma pack(1)は、その構造体の定義に__attribute__((packed))をアタッチするのと同じ効果をインスタンスのレイアウトに与えることがわかります。ただし、同じ目的を達成したとしても、同じことではありません。両方の動作と効果はC++仕様の範囲外であり、GCCは他の点でそれらを異なる方法で処理する権利の範囲内にあります。

ただし、属性を使用して構造体メンバーの配置に影響を与える場合は、少なくともいくつかの属性をメンバーごとに適用する必要があります。例えば ​​...

_struct foo1 {
    char a;
    int b __attribute__((aligned(n)));
} __attribute__((packed));
_

...と同じ効果があるかもしれません...

_#pragma pack(Push, n)
struct foo2 {
    char a;
    int b;
};
#pragma pack(pop)
_

...、nによって異なります。

8
John Bollinger