プリプロセッサとインクルードガード(C/C++)

C/C++にてファイル分割を行う際に問題となる点がありました。
ヘッダファイルには各種ソースファイルの共通部分を置きたいのですが
何度も読み込まれる可能性があるにも関わらず定義は1度しか行えないということです。
(以下を参考:宣言と定義とファイル分割)


このときに役に立つのがプリプロセッサです。
プリプロセッサとはコンパイラに対する命令群のことです。
#includeや#defineなどが該当します。


さて、いくつかのプリプロセッサを見てみましょう。
#include AAA // AAAを読み込みなさい。
#define AAA // AAAを定義しなさい。
#ifdef AAA // AAAが定義されたら以下を読み込め。
#ifndef AAA // AAAが定義されていなかったら以下を読み込め。
#endif // #ifdefの範囲はここまで。


ではインクルードガードを例にとって考えてみましょう。

// header.h
#ifndef HEADER_H
#define HEADER_H

struct Sample { int x; };

#endif // HEADER_H


順を追って解説しましょう。
最初の一行目#ifndef HEADER_HではHEADER_Hが定義されているかどうかに注目します。
定義されている場合は#endifまで読み飛ばします。
しかしながら1回目に読み込まれた場合は何も定義されていませんので通常通り読み込みます。


次の行の#define HEADER_Hです。ここでようやくHEADER_Hを定義します。
よく#define AAA 10のように定義しますが、ここでは内容は必要ありません。定義するだけです。
(最近はconstがよく利用されますが)


さて、1回目は普通に読み込まれました。
素晴らしいのは2回目以降です。


既にHEADER_Hは定義されているので、#ifndefのところから#endifまで読み飛ばしが発生されます。
これによってstructは2重に定義されることが防がれるようになりました。


この手法はインクルードガードと呼ばれるものです。
他のやり方として#pragmaを使うこともできます。


最初にアンダースコア"_"をつけるのは、予約済みであることが多いのでやめたほうが良い。