8

Visual C++ では、コンパイラ スイッチ ( /Zp) と、pack構造体メンバーの配置に影響を与えるプラグマの両方が提供されています。しかし、私はそれらがどのように機能するかについて、いくつかの誤解を持っているようです。

MSDNによると、特定のアライメント値 n に対して、

メンバーの位置合わせは、n の倍数またはメンバーのサイズの倍数のいずれか小さい方の境界上にあります。

pack 値が 8 バイト (デフォルト) であるとします。構造体内では、サイズが 8 バイト未満のメンバーは、それ自体のサイズの倍数のオフセットになると思います。サイズが 8 バイト以上のメンバーは、8 バイトの倍数のオフセットになります。

次に、次のプログラムを実行します。

#include <tchar.h>

#pragma pack(8)

struct Foo {
    int i1;
    int i2;
    char c;
};

struct Bar {
    char c;
    Foo foo;
};

int _tmain(int argc, _TCHAR* argv[]) {
    int fooSize = sizeof(Foo); // yields 12
    Bar bar;
    int fooOffset = ((int) &bar.foo) - ((int) &bar); // yields 4

    return 0;
}

構造体のFooサイズは 12 バイトです。したがって、メンバーは実際にはオフセット 4 にあるのに、オフセット 8 (8 の倍数) にあるBarと予想されます。なぜですか?Foo

また、Foo実際には 4+4+1 = 9 バイトのデータしかありません。コンパイラは、最後にパディング バイトを自動的に追加します。しかし、再び、8 バイトのアラインメント値が与えられた場合、4 ではなく 8 の倍数にパディングすべきではないでしょうか?

説明をいただければ幸いです。

4

3 に答える 3

8

あなたの抜粋は、これを「小さい方」と説明しています。32 ビット プラットフォームでは、anintは 4 バイトです。4 は 8 より小さいため、4 バイトのアラインメントがあります。

プラグマにより、packアンパックではなくパックが実行されます。理由がなければパディングしません。

于 2012-04-21T10:26:04.577 に答える
5

そもそもアライメントが重要な理由を覚えておいてください。バイトを多重化することなく、CPUがメモリをすばやく読み取れるようにするためにあります。CPU は一度に構造体を読み取ることはなく、そのメンバーのみにアクセスします。したがって、Foo 構造体が 12 バイトであるという事実は重要ではありません。そのメンバーの配置のみが重要です。4 を超えるアライメント要件を持つ Foo メンバーがない場合、Bar.foo メンバーは 4 にアライメントするだけで済みます。

Foo が 9 バイトではなく 12 バイトであることも説明に使用できます。コンパイラは、最後に 3 バイトのパディングを追加して、Foo の配列に各配列要素のメンバーが正しく配置されるようにします。

于 2012-04-21T10:58:22.240 に答える
2

あなたの引用が言うように-8バイトのアライメントをテストするには、8バイト以上のデータ型が必要です。いくつかの明示的なサイズの型のサンプルを次に示します。また、小さな要素を最後に配置しても、パディングは構造体の最後からドロップされる可能性があるため、表示されません。

#include <stdio.h>
int
main(int argc, char *argv[])
{
    struct S {
        __int64 a;
        __int8  b;
        __int64 c;
    };
#pragma pack(push,1)
    struct T {
        __int64 a;
        __int8  b;
        __int64 c;
    };
#pragma pack(pop)
#pragma pack(push,8)
    struct U {
        __int64 a;
        __int8  b;
        __int64 c;
    };
    struct B {
        __int8 c;
        struct U s;
    };
#pragma pack(pop)

    printf("S %d T %d U %d B %d\n",
           sizeof(struct S), sizeof(struct T),
           sizeof(struct U), sizeof(struct B));
    return 0;
}

これを VC 2010 でコンパイルします。

C:\src>cl -nologo -W3 -Od packing.c && packing.exe
packing.c
S 24 T 17 U 24 B 32
于 2012-04-21T10:29:14.103 に答える