このページはC++11に採用された言語機能の変更を解説しています。
のちのC++規格でさらに変更される場合があるため関連項目を参照してください。
概要
alignas()は、コンパイラに対し変数をメモリ上の特定の位置に配置(アライメント)するように要求するキーワードである。「アライン アズ (align as)」と読む。
例えば4バイト境界の位置にアライメントした場合、変数は4の倍数のアドレスに配置され、8バイト境界の位置にアライメントした場合、変数は8の倍数のアドレスに配置される。
仕様
alignas() は変数宣言やクラスのメンバ変数宣言に使用するか、構造体やクラスの宣言時に使用できる。
変数やクラスのメンバ変数宣言時に使用した場合、宣言した変数をアライメントする。
alignas(32) int i; //32バイト境界にアライメントする
構造体やクラスの宣言時に使用した場合、その型のインスタンス全てをアライメントする。
struct alignas(32) hoge {
};
hoge a; //32バイト境界にアライメントする
hoge b; //32バイト境界にアライメントする
alignas(定数)は、定数の値でアライメントをする。0または0として評価される値を指定したときは何も起きない。
alignas(型)は、alignas(alignof(型))と等価である。ある型 A のアライメントを別の型 B にも適用したいときalignas(A) B hoge;のように書ける。ただし、A のアライメントは B のアライメント以上でなければならない。
ただしGCC 4.9ではalignas(0)は使えず、下記のエラーを出力する。
error: requested alignment is not a positive power of 2
また、ひとつの宣言に指定したすべてのalignasを合わせた効果が、alignasを指定しなかった場合に要求されるアライメントよりも弱い場合、プログラムは不適格となる。例えばintのアライメントが4である環境では、alignas(1) int i;は不適格である。一方、alignas(1) alignas(4) int i;は、合わせた効果が4バイト境界へのアライメントとなるため適格である。
なお、GCCは16.2時点でalignas(1) int i;をエラーにも警告にもしないが、Clangではエラーとなる。
例
#include <iostream>
struct test {
alignas(1) char c1, c1_n;
alignas(2) char c2, c2_n;
alignas(4) int i4, i4_n;
alignas(8) int i8, i8_n;
alignas(16) int i16, i16_n;
alignas(8) alignas(16) int i8_16, i8_16_n;
};
int distance(void *a, void *b)
{
return reinterpret_cast<char*>(a) - reinterpret_cast<char*>(b);
}
int main()
{
//Zero is ill-formed in GCC 4.9.
//alignas(0) test a;
test t;
std::cout <<
"alignas(1) char c1: " << distance(&t.c1_n, &t.c1) << std::endl <<
"alignas(2) char c2: " << distance(&t.c2_n, &t.c2) << std::endl <<
"alignas(4) int i4: " << distance(&t.i4_n, &t.i4) << std::endl <<
"alignas(8) int i8: " << distance(&t.i8_n, &t.i8) << std::endl <<
"alignas(16) int i16: " << distance(&t.i16_n, &t.i16) << std::endl;
std::cout <<
"alignas(8) alignas(16) int i8_16: " <<
distance(&t.i8_16_n, &t.i8_16) << std::endl;
return 0;
}
出力
alignas(1) char c1: 1
alignas(2) char c2: 2
alignas(4) int i4: 4
alignas(8) int i8: 8
alignas(16) int i16: 16
alignas(8) alignas(16) int i8_16: 16
この機能が必要になった背景・経緯
下記の理由などにより、変数のアライメントをする必要がある。
- メモリアクセスの最適化を行う
- ハードウェアの制約を満たす
- 同じアドレスに異なるデータを格納する
C++98で変数のアライメントを行うにはコンパイラの拡張機能を利用するしかなく、コンパイラごとに異なる記述を行う必要があったが、C++11ではどのコンパイラでも同じ記述でアライメントができる。
検討されたほかの選択肢
N2341 からはわからない、恐らくないと思われる。
参照