12

アライメントについてもっと知りたいです。Microsoft コンパイラ (Visual Studio 2012 Express) が次のコード スニペットの配置について不平を言うのはなぜですか?

__declspec(align(16)) class Foo
{
public:
    virtual ~Foo() {}
    virtual void bar() = 0;
};

これはコンパイラが私に提示する警告です:

warning C4324: 'Foo' : structure was padded due to __declspec(align())

クラスに仮想メソッドがあるかどうかは問題ではありません。空のクラスの場合でも、コンパイラは同じ警告メッセージを出します。空のクラスはどのように配置されますか? コンパイラはこのクラスをどのようにパディングしますか?

4

4 に答える 4

19

警告は、必ずしも何か間違ったことをしたことを意味するわけではありませんが、この動作を意図していなかった可能性があることを示しています。コンパイラは、開発者が警告する価値があると考えたものについて警告することが許可されていることに注意してください。原則として、13 日の金曜日にコンパイルすることについて警告を受けることもできます。

この特定のケースでは、アラインメントを指定するときに、クラスを大きくしたくないという想定がおそらくあります。したがって、指定したアライメント要件のためにクラスが大きくなった場合、間違いを犯した可能性は低くありません。

もちろん、なぜアラインメント要件がクラスを大きくするのかという疑問が残ります。これで、標準の世界に戻りました (ただし、__declspecそれ自体は Microsoft の拡張機能であり、標準ではありません)。C++ 標準では、配列内でオブジェクトが間にスペースを入れずに連続している必要があります。したがって、オブジェクトを 16 バイト境界に揃える必要がある場合、オブジェクトのサイズは 16 の倍数でなければなりません。メンバーのサイズ (明示的および暗黙的の両方) が必要なサイズを与えない場合、コンパイラは未使用のバイトをオブジェクトに追加します。これらのバイトはパディングと呼ばれます。このパディングは、配列のメンバーではないオブジェクトにも存在することに注意してください。

現在、クラスには暗黙的な仮想ポインターのみが含まれています (仮想関数が含まれているため)。アーキテクチャによっては、おそらく 4 または 8 バイトの大きさです。16 バイトのアラインメントを要求したため、コンパイラは、サイズを 16 の倍数にするために 12 または 8 バイトのパディングを追加する必要があります。そして、これはコンパイラが警告するものです。

于 2012-09-19T19:41:03.933 に答える
2

x86ではFooは4バイトを必要とするため、12バイトのパッドが必要です。x64ではFooは8バイトを必要とするため、8バイトのパッドが必要です。

于 2012-09-19T19:25:36.297 に答える
2

この警告はsizeof__declspec(align()). それは物事を壊す可能性があるため、警告です。

もちろん、空のクラスにはサイズがあり、0 より大きい必要があるため、少なくとも 1 です。

通常、サイズはアラインメントによって変化しませんが、クラスのパディングされていないサイズよりも大きいアラインメントを指定したため、あなたの場合は変化します。また、C では、型のアラインメントをそのサイズよりも小さくすることはできません。実際には、サイズはアラインメントの倍数でなければならないため、サイズはアラインメントに合わせて大きくなります。

サイズがアライメントの倍数でなければならないのはなぜですか? さて、このタイプの配列を想像してみてください。連続する要素は正確に で区切る必要がsizeof(T)ありますが、各オブジェクトはメモリ アドレスのアラインメントの倍数にある必要があります。この方程式の唯一の解決策sizeof(T)は、アラインメントの (null 以外の) 倍数でなければならないということです。

于 2012-09-19T19:27:32.840 に答える
2

__declspec(align())またはを使用して構造体のアラインメントを増やすと、 alignas()構造体がより厳密にアラインメントされるだけでなく、次の規則に従って構造体の最後にパディングが必要になる場合があります。

構造体のサイズは、最後のメンバーの末尾のオフセット以上のアラインメントの最小倍数です。

言い換えると、構造体のアラインメントを 16 に増やす場合、構造体のサイズも 16 の倍数であることを確認することをお勧めします。 (コンパイラは、構造体のサイズにどれだけ依存しているか、この規則を知っているかどうかを判断できないため、警告を発行します)。

于 2016-08-31T10:09:10.773 に答える