C++の基礎 - プリプロセッサ
概要
プリプロセッサはC++コンパイルの最初の段階で動作する重要な機能である。
ソースコードがコンパイラに渡される前に、プリプロセッサがテキスト操作を行う。
主な役割として、ディレクティブの処理がある。
ディレクティブは#で始まる特殊な命令であり、コードの条件付きコンパイル、マクロの定義・展開等を制御する。
例えば、#includeディレクティブは指定されたファイルの内容をその場所に挿入する。
これにより、ヘッダファイルの内容を効率的にソースコードに取り込むことができる。
#defineディレクティブはマクロを定義する。
マクロは、単純なテキスト置換、引数を取る関数のような複雑なものまで可能である。
これにより、コードの再利用性や可読性を向上させることができる。
条件付きコンパイルも重要な機能である。
#ifdef、#ifndef等のディレクティブを使用して、特定の条件下でのみコードをコンパイルすることができる。
これは異なるプラットフォームやコンパイラ向けのコードを管理する際に非常に有効である。
プリプロセッサは以下に示すような順序で動作する。
- トリグラフの置換 (古い機能で、現代ではあまり使用されていない)
- 行連結 (バックスラッシュで終わる行を次の行と連結)
- トークン化 (ソースコードをトークンに分割)
- ディレクティブの処理
- マクロ展開
- 文字列リテラル内のエスケープシーケンスの変換
プリプロセッサの過度の使用は可読性を損なう可能性があり、デバッグを困難にすることがある。
また、名前空間を汚染する可能性もあるため、現代のC++では可能な限りプリプロセッサの使用を避け、代わりにconstexpr、テンプレート、インライン関数等の言語機能を使用することが推奨されている。
条件付きインクルード
条件付きインクルードを行うには、__has_includeプリプロセッサディレクティブを使用する必要がある。
ただし、__has_includeは、C++ 17以降で利用可能な機能である。
#if __has_include("hoge.h")
#include "hoge.h"
#elif __has_include("piyo.h")
#include "piyo.h"
#endif
- まず __has_include("hoge.h") では、hoge.hファイルの存在を確認する。
- hoge.hファイルが存在する場合は、それをインクルードする。
- hoge.hファイルが存在しない場合は、__has_include("piyo.h") で piyo.hファイルの存在を確認する。
- piyo.hファイルが存在する場合は、それをインクルードする。
※注意
この方法は、コンパイル時にチェックを行う。
実行時のファイル存在チェックではないことに注意する。