C++プログラミングにおいて、時にはコンパイラに対して標準機能の範囲を超える、より詳細な指示を与えたい場面があります。例えば、「この関数はDLLからエクスポートする」「この構造体は特定のメモリ境界に配置してほしい」といったケースです。
この記事では、そうした目的で使われる二つの代表的なコンパイラ拡張機能、Microsoft Visual C++の**__declspec
と、GCC/Clangの__attribute__
**について、その使い方と注意点、そして現代C++における標準的なアプローチを解説します。
コンパイラへの指示―「属性」とは?
属性(Attribute)とは、変数、関数、クラスといったプログラムの要素に対して追加の情報を付与し、コンパイラの動作を制御するためのメタデータです。
これらを利用することで、以下のようなことが可能になります。
- 最適化のヒントを与える
- メモリ配置(アライメント)を制御する
- 特定のコーディングミスに対して警告を出す
- ライブラリ(DLL/共有ライブラリ)のインポート・エクスポートを制御する
Microsoft Visual C++の __declspec
__declspec
(”declaration specifier”の略)は、Microsoft Visual C++ (MSVC) コンパイラで利用できるキーワードです。通常、修飾したい変数や関数の宣言の前に記述します。
__declspec
の使用例
例1: DLLからの関数エクスポート
共有ライブラリ(DLL)を作成する際、外部から呼び出せるように関数を公開(エクスポート)する必要があります。
// この関数をDLLからエクスポートする
__declspec(dllexport) int AddNumbers(int a, int b) {
return a + b;
}
例2: 非推奨の警告
古い関数を非推奨にし、使われた際にコンパイル警告を出すことができます。
// この関数は古いため、使用すると警告が出る
__declspec(deprecated("Please use NewFunction() instead."))
void OldFunction() {
// ...
}
GCC/Clangの __attribute__
__attribute__
は、主にGCCや、それと互換性を持つClangなどのコンパイラで利用できるキーワードです。二重の丸括弧 ((...))
を使って属性を指定し、通常は修飾したい宣言の後に記述します。
__attribute__
の使用例
例1: 決して戻らない関数
exit()
のように、呼び出されたら決して処理が戻ってこない関数であることをコンパイラに伝えます。これにより、より良い最適化や警告の抑制が期待できます。
#include <cstdlib>
void TerminateProgram() __attribute__((noreturn));
void TerminateProgram() {
// ...
exit(1);
}
例2: メモリアライメントの指定
特定の構造体を、パフォーマンス上の理由から16バイト境界に配置したい場合などに使用します。
// この構造体は16バイト境界に配置される
struct VectorData {
float x, y, z, w;
} __attribute__((aligned(16)));
現代的な解決策:標準C++属性 [[...]]
ここまで紹介した__declspec
と__attribute__
は、非常に強力ですが、それぞれ特定のコンパイラでしか動作しないため、コードの移植性を損なう原因となります。
この問題を解決するため、C++11からは**[[...]]
という形式の標準属性**が導入されました。コンパイラ間で互換性があり、現代的なC++ではこちらを使用することが強く推奨されます。
標準属性による書き換え
上記の例のいくつかは、標準属性で置き換えることができます。
- 非推奨の警告C++
// 標準的な方法で非推奨を指定 [[deprecated("Please use NewFunction() instead.")]] void OldFunction() { // ... }
- 決して戻らない関数C++
// 標準的な方法でnoreturnを指定 [[noreturn]] void TerminateProgram() { // ... }
ただし、DLLのエクスポート (dllexport
) のように、まだ標準属性として定義されていない機能も存在します。そういった場合は、依然としてコンパイラ固有の拡張機能に頼る必要があります。
まとめ
__declspec
と __attribute__
は、コンパイラの動作を細かく制御するための強力なツールですが、それぞれ特定のコンパイラに依存する非標準の機能です。
コードの移植性と将来性を考慮し、 「[[deprecated]]
のように標準属性で代替できるものは、積極的に標準属性を使う」 「DLLエクスポートのように、どうしても必要な場合のみコンパイラ固有の機能を使う」 という使い分けをすることが、質の高いC++コードを書く上での鍵となります。