メモリアライメント:alignof / alignasの使い方は?


82

現在、共有メモリを使用しています。

わからないalignofalignas

cppreferenceが不明確です:alignof「alignment」を返しますが、「alignment」とは何ですか?次のブロックを整列させるために追加するバイト数?パッド入りサイズ?スタックオーバーフロー/ブログエントリも不明確です。

誰かが明確に説明できますalignofalignas


1
cppreferenceは、チュートリアルではなくリファレンスになろうとしています
Cubbi 2013年

1
@Cubbi:cplusplus.comでも確認できます。サイトが優れているか、特定のトピックについてはcplusplusが優れているか、他のcppreferenceが優れているかについての議論があります。どちらのサイトも、特定の時期に十分ではないことがわかりました
CoffeDeveloper

2
@DarioOO cppreferenceがalignofページ上の配置の概念を説明していない理由に答えているだけでした(現在、進行中のオブジェクトページで説明しています)。cplusplus.comがどのように関連しているかわかりません。
cubbi 2014年

回答:


82

アラインメントは、値の最初のバイトを格納できるメモリ位置の制限です。(プロセッサのパフォーマンスを向上させ、特定のアラインメントを持つデータでのみ機能する特定の命令の使用を許可する必要があります。たとえば、SSEは16バイトにアラインメントする必要があり、AVXは32バイトにアラインメントする必要があります。)

16のアラインメントは、16の倍数であるメモリアドレスが唯一の有効なアドレスであることを意味します。

alignas

必要なバイト数に強制的に調整します。2の累乗にのみ調整できます:1、2、4、8、16、32、64、128、...

#include <cstdlib>
#include <iostream>

int main() {
    alignas(16) int a[4];
    alignas(1024) int b[4];
    printf("%p\n", a);
    printf("%p", b);
}

出力例:

0xbfa493e0
0xbfa49000  // note how many more "zeros" now.
// binary equivalent
1011 1111 1010 0100 1001 0011 1110 0000
1011 1111 1010 0100 1001 0000 0000 0000 // every zero is just a extra power of 2

他のキーワード

alignof

とても便利です、あなたは次のようなことをすることはできません

int a[4];
assert(a % 16 == 0); // check if alignment is to 16 bytes: WRONG compiler error

しかし、あなたはすることができます

assert(alignof(a) == 16);
assert(alignof(b) == 1024);

実際には、これは単純な「%」(モジュラス)演算よりも厳密であることに注意してください。実際、1024バイトにアラインされたものは、必ず1、2、4、8バイトにアラインされますが、

 assert(alignof(b) == 32); // fail.

つまり、より正確に言うと、「alignof」は、何かが整列されている場合に2の最大の累乗を返します。

また、alignofは、基本的なデータ型の最小アライメント要件を事前に知るための優れた方法です(charsの場合は1、floatの場合は4などを返す可能性があります)。

まだ合法:

alignas(alignof(float)) float SqDistance;

次に、16の倍数である、次に使用可能なアドレスに16の配置を持つものが配置されます(最後に使用されたアドレスからの暗黙のパディングがある場合があります)。


10
とは異なりsizeof、にalignofのみ適用できtype-idます。
neverhoodboy 2014

であるalignof()(相手alignas())コンパイル時に評価され、これがない実行時のオーバーヘッド?
無感覚2014年

番号。それは不可能であり、コンパイラはごくまれに最適化としてそれを行うかもしれませんが、一般に、2つの関数を評価する前にメモリアドレスがどのように整列されるかを知りません。私の例で生成されたアセンブリを見てください:goo.gl/ZbemBF
CoffeDeveloper 2014

1
@Serthy明確にすることalignof 、コンパイル時定数です。alignasはそうではなく、new(標準の要件)の実装、またはカスタムstdアロケータによってサポートされる必要があります
aidiakapi 2016年

良い答えですがstruct、構造体の処理とメンバーが必要staticです。特にClangのようなコンパイラでalignas__attribute__((aligned))、よりもはるかに厄介であることが判明しています。
jww 2016年

11

位置合わせはパディングではありません(ただし、位置合わせの要件を満たすためにパディングが導入される場合があります)。これは、C ++タイプの本質的なプロパティです。標準化するには(3.11[basic.align]

オブジェクトタイプには、そのタイプのオブジェクトを割り当てることができるアドレスに制限を課す配置要件(3.9.1、3.9.2)があります。アラインメントは、特定のオブジェクトを割り当てることができる連続するアドレス間のバイト数を表す実装定義の整数値です。オブジェクトタイプは、そのタイプのすべてのオブジェクトに配置要件を課します。より厳密な配置は、配置指定子(7.6.2)を使用して要求できます。


1
とても興味深い。いくつか例を挙げていただけませんか。alignof(struct X)== sizeof(struct X)ですか?何故なの ?
Offirmo 2013年

1
@Offirmoいいえ、ただし、一貫性がある場合を除きます。正常struct X { char a; char b}なシステムでは、サイズ2とアライメント要件1があります(charは任意のアドレスに割り当てることができるため、任意のアドレスに割り当てることができます)
Cubbi 2013年

1のアライメント要件???? わかりました。アライメントは常に「自然な」32ビット/ 64ビット境界上にあると思いましたが、明らかにそうではありませんでした。それは物事を説明しています...したがって、通常のマシンでは、alignof()の結果は常に4(32ビット)または8(64ビット)で最大になりますか?
Offirmo 2013年

@Offirmoの「自然な」alignofalignof(std::max_align_t)16、私のLinux上にある(-m32または-m64のどちらをコンパイルするかに関係なく)で最大になりますが、alignas
Cubbi 2013年

7

各タイプには、位置合わせの要件があります。一般に、これは、データ型の特定のメンバーに到達するためにCPUに複数の読み取り/書き込みアクセスを生成させることなく、タイプの変数に効率的にアクセスできるようにするためです。さらに、変数全体の効率的なコピーも保証します。alignof指定されたタイプの配置要件を返します。

alignasデータ型の整列を強制するために使用されます(そのalignofデータ型が返すものよりも厳密でない限り)


3

配置は、メモリアドレスに関連するプロパティです。簡単に言うと、アドレスXがZに位置合わせされている場合、xはZの倍数、つまりX = Zn +0です。ここで重要なのは、Zは常に2の累乗であるということです。

アラインメントはメモリアドレスのプロパティであり、2の累乗を法とする数値アドレスとして表されます。たとえば、4を法とするアドレス0x0001103Fは3です。このアドレスは4n + 3にアラインされていると言われます。ここで、4は2.アドレスのアラインメントは、選択した2の累乗に依存します。8を法とする同じアドレスは7です。アドレスのアラインメントがXn + 0の場合、アドレスはXにアラインメントされていると言われます。

上記のステートメントは、Microsoft C ++リファレンスに記載されています。

データ項目がそのサイズに合わせられたアドレスでメモリに格納されている場合、そのデータ項目は自然に位置合わせされていると言われます。そうでない場合は位置がずれています。たとえば、サイズが4バイトの整数変数が4にアラインされたアドレスに格納されている場合、変数は自然にアラインされていると言えます。つまり、変数のアドレスは4の倍数である必要があります。

コンパイラは常にミスアライメントを回避しようとします。単純なデータ型の場合、アドレスは、バイト単位の変数のサイズの倍数になるように選択されます。コンパイラーは、自然な位置合わせとアクセスのために構造体の場合にも適切にパディングします。ここで、構造体は、構造体内のさまざまなデータ項目の最大サイズに位置合わせされます。例:

    struct abc
   {
        int a;
        char b;
   };

ここで、構造abcは4に整列されていますいます。これは、明らかに1バイト(charメンバーのサイズ)より大きいintメンバーのサイズです。

アラインアス

この指定子は、構造、クラスなどのユーザー定義タイプを2の累乗である特定の値に揃えるために使用されます。

alignof

これは、構造体またはクラスタイプが整列されている値を取得するための一種の演算子です。例えば:

#include <iostream>
struct alignas(16) Bar
{
    int i; // 4 bytes
    int n; // 4 bytes
    short s; // 2 bytes
};
int main()
{
    std::cout << alignof(Bar) << std::endl; // output: 16
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.