GCCにおけるalignasのエラー

こんにちはtatsyです。

最近C++11/14の機能を多用している私ですが、C++0xからの新機能であるalignasについて、少し躓いた点があるので、使用法と注意点をまとめておきたいと思います。

C++におけるアラインメント


C++でのアラインメントとは、データをメモリ上に置く際に、ある区切りのいい数字の倍数から始まる場所にデータを置いてくださいという意味の数字です。

例えばSIMDの拡張命令を使おうと思ったときにfloatを4つ分処理しようとするなら、このfloatの4つ組は4×4で16バイト単位にアラインメントされていないいけないため、このような指定が必要になるわけです。

C++11のalignas


C++0x以前はGCCやVisual Studioなどのコンパイラごとにアラインメントを指定するためのコンパイラ拡張が実装されていました。

このコンパイラ間の違いを無くすためのC++11ではalignasという型指定子が新しく提供されています。以下に書き方の違いをまとめて見ました。

// GCC
__attribute__((aligned(16))) float fvals[4];

// Visual Studio
__declspec(align(16)) float fvals[4];

// C++11
alignas(16) float fvals[4];

これを見るとalignasが一番単純で分かり易そうな気がします。

GCCでalignasを使う時の注意点


僕が調べた限りだとClangとVisual Studioではこのエラーは起きないのですが、GCCではalignasとGCC独自の言語拡張である___attribute__を組み合わせるとコンパイルエラーになります。

例えば、GCCではクラスや関数をライブラリのシンボルリストに登録するかどうかを決めるものとしてvisibilityというのを指定できます。

class __attribute__((visibility("default"))) MyClass {};

これをalignasと組み合わせて、

class __attribute__((visibility("default"))) alignas(16) MyClass {};

のようにすると、コンパイラが構文解析に失敗して大量にエラーを吐いてきます。

GCCのissueリストにも報告されているようで、これを回避するには今までどおりアラインメントも__attribute__で指定するしかないみたいです。

class __attribute__((visibility("default"))) __attribute__((aligned(16)))
MyClass{};

これをみて、GCCはもう時代遅れかなぁなんて思ったりもしますが、クロスプラットフォームを意識するなら、GCCも拾っとかなきゃという気もしたりしています。