AlignmentAlignment

C++ の低レベルの機能の 1 つは、特定のハードウェア アーキテクチャを最大活用するために、メモリ内のオブジェクトの正確な配置を指定できる機能です。One of the low-level features of C++ is the ability to specify the precise alignment of objects in memory to take maximum advantage of a specific hardware architecture. 既定では、コンパイラは、クラスと構造体のメンバーのサイズ値を、2バイト境界、、、および4バイト境界 (、、、 bool char short int long float long long double および long double 8 バイト境界) に配置します。By default, the compiler aligns class and struct members on their size value: bool and char on 1-byte boundaries, short on 2-byte boundaries, int, long, and float on 4-byte boundaries, and long long, double, and long double on 8-byte boundaries.

ほとんどのシナリオでは、既定の配置が既に最適化されているため、配置について心配する必要はありません。In most scenarios, you never have to be concerned with alignment because the default alignment is already optimal. ただし、場合によっては、データ構造にカスタム配置を指定することで、パフォーマンスを大幅に向上させたり、メモリを節約したりすることができます。In some cases, however, you can achieve significant performance improvements, or memory savings, by specifying a custom alignment for your data structures. Visual Studio 2015 より前では、Microsoft 固有のキーワードとを使用し __alignof て、 __declspec(align) 既定値よりも大きいアラインメントを指定できました。Before Visual Studio 2015 you could use the Microsoft-specific keywords __alignof and __declspec(align) to specify an alignment greater than the default. Visual Studio 2015 以降では、 alignof alignas コードの移植性を最大にするために、c++ 11 の標準キーワードとを使用する必要があります。Starting in Visual Studio 2015 you should use the C++11 standard keywords alignof and alignas for maximum code portability. 新しいキーワードは、内部的には Microsoft 固有の拡張機能と同じように動作します。The new keywords behave in the same way under the hood as the Microsoft-specific extensions. これらの拡張機能のドキュメントは、新しいキーワードにも適用されます。The documentation for those extensions also applies to the new keywords. 詳細については、「 alignof Operator and align」を参照してください。For more information, see alignof Operator and align. C++ 標準では、ターゲットプラットフォームのコンパイラの既定値よりも小さい境界に対してはパッキング動作が指定されていないため、その場合でも Microsoft を使用する必要があり #pragma pack ます。The C++ standard doesn't specify packing behavior for alignment on boundaries smaller than the compiler default for the target platform, so you still need to use the Microsoft #pragma pack in that case.

カスタム配置でのデータ構造のメモリ割り当てには、 aligned_storage クラスを使用します。Use the aligned_storage class for memory allocation of data structures with custom alignments. Aligned_union クラスは、重要なコンストラクターまたはデストラクターを持つ共用体のアラインメントを指定するためのものです。The aligned_union class is for specifying alignment for unions with non-trivial constructors or destructors.

アラインメントとメモリアドレスAlignment and memory addresses

配置は、2 の累乗の数値のアドレスの剰余として表現される、メモリ アドレスのプロパティです。Alignment is a property of a memory address, expressed as the numeric address modulo a power of 2. たとえば、0x0001103F モジュロ4というアドレスは3です。For example, the address 0x0001103F modulo 4 is 3. このアドレスは、のようになります。ここで、4は選択された2の累乗を示します。That address is said to be aligned to 4n+3, where 4 indicates the chosen power of 2. アドレスの配置は、選択した2の累乗によって異なります。The alignment of an address depends on the chosen power of 2. 同じアドレスの 8 の剰余は 7 です。The same address modulo 8 is 7. 配置が Xn+0 の場合、アドレスが X に配置されると言われます。An address is said to be aligned to X if its alignment is Xn+0.

Cpu は、メモリに格納されているデータを操作する命令を実行します。CPUs execute instructions that operate on data stored in memory. データは、メモリ内のアドレスによって識別されます。The data are identified by their addresses in memory. 1つの datum にもサイズがあります。A single datum also has a size. そのアドレスがサイズに合わせて調整されている場合は、自然にアラインされた datum を呼び出します。We call a datum naturally aligned if its address is aligned to its size. それ以外の場合は、ミスアライメントと呼ばれます。It's called misaligned otherwise. たとえば、8バイトの浮動小数点の datum は、それを識別するために使用されるアドレスに8バイトのアラインメントがある場合に、自然にアラインされます。For example, an 8-byte floating-point datum is naturally aligned if the address used to identify it has an 8-byte alignment.

データ配置のコンパイラ処理Compiler handling of data alignment

コンパイラは、データの不整合を防ぐようにデータの割り当てを試行します。Compilers attempt to make data allocations in a way that prevents data misalignment.

単純なデータ型の場合、コンパイラは、データ型のバイト単位のサイズの倍数であるアドレスを割り当てます。For simple data types, the compiler assigns addresses that are multiples of the size in bytes of the data type. たとえば、コンパイラは、4の倍数である型の変数にアドレスを割り当て long ます。この場合、アドレスの下2ビットを0に設定します。For example, the compiler assigns addresses to variables of type long that are multiples of 4, setting the bottom 2 bits of the address to zero.

コンパイラは、構造体の各要素を自然に配置するように構造体を埋め込みます。The compiler also pads structures in a way that naturally aligns each element of the structure. 次のコード例では、構造について考えてみ struct x_ ます。Consider the structure struct x_ in the following code example:

struct x_
{
   char a;     // 1 byte
   int b;      // 4 bytes
   short c;    // 2 bytes
   char d;     // 1 byte
} bar[3];

コンパイラは自然な配置を強制するようにこの構造体を埋めます。The compiler pads this structure to enforce alignment naturally.

次のコード例は、コンパイラが埋め込まれた構造体をメモリ内に配置する方法を示しています。The following code example shows how the compiler places the padded structure in memory:

// Shows the actual memory layout
struct x_
{
   char a;            // 1 byte
   char _pad0[3];     // padding to put 'b' on 4-byte boundary
   int b;            // 4 bytes
   short c;          // 2 bytes
   char d;           // 1 byte
   char _pad1[1];    // padding to make sizeof(x_) multiple of 4
} bar[3];

どちらの宣言も sizeof(struct x_) 12 バイトとして返されます。Both declarations return sizeof(struct x_) as 12 bytes.

2 番目の宣言には、埋め込みの 2 つの要素が含まれています。The second declaration includes two padding elements:

  1. char _pad0[3]``int b4 バイト境界上にメンバーを配置する場合は。char _pad0[3] to align the int b member on a 4-byte boundary.

  2. char _pad1[1]構造体の配列要素を struct _x bar[3]; 4 バイト境界に揃える場合は。char _pad1[1] to align the array elements of the structure struct _x bar[3]; on a four-byte boundary.

パディングは、 bar[3] 自然なアクセスを可能にするようにの要素を配置します。The padding aligns the elements of bar[3] in a way that allows natural access.

次のコード例は、配列のレイアウトを示してい bar[3] ます。The following code example shows the bar[3] array layout:

adr offset   element
------   -------
0x0000   char a;         // bar[0]
0x0001   char pad0[3];
0x0004   int b;
0x0008   short c;
0x000a   char d;
0x000b   char _pad1[1];

0x000c   char a;         // bar[1]
0x000d   char _pad0[3];
0x0010   int b;
0x0014   short c;
0x0016   char d;
0x0017   char _pad1[1];

0x0018   char a;         // bar[2]
0x0019   char _pad0[3];
0x001c   int b;
0x0020   short c;
0x0022   char d;
0x0023   char _pad1[1];

alignof および alignasalignof and alignas

alignas 型指定子は、変数およびユーザー定義型のカスタムアラインメントを指定するための移植可能な C++ 標準の方法です。The alignas type specifier is a portable, C++ standard way to specify custom alignment of variables and user defined types. また、演算子は、 alignof 指定された型または変数のアラインメントを取得するための、標準の移植可能な方法です。The alignof operator is likewise a standard, portable way to obtain the alignment of a specified type or variable.

Example

alignas は、クラス、構造体、共用体、または個々のメンバーに対して使用できます。You can use alignas on a class, struct or union, or on individual members. 複数の alignas 指定子が検出されると、コンパイラは最も厳格なもの (最も大きな値を持つもの) を選択します。When multiple alignas specifiers are encountered, the compiler will choose the strictest one, (the one with the largest value).

// alignas_alignof.cpp
// compile with: cl /EHsc alignas_alignof.cpp
#include <iostream>

struct alignas(16) Bar
{
    int i;       // 4 bytes
    int n;      // 4 bytes
    alignas(4) char arr[3];
    short s;          // 2 bytes
};

int main()
{
    std::cout << alignof(Bar) << std::endl; // output: 16
}

関連項目See also

データ構造の配置Data structure alignment