C++の常識

条件コンパイルによる重複定義の回避


ヘッダファイル

 ヘッダファイルとはファイル名の最後に拡張子.h が付いたファイルのことです。

 ヘッダファイルの中で変数、関数、クラスなどを定義しておくと、そのヘッダファイルを他のファイルからインクルードすることにより、これら変数、関数、クラスを使用できるようになります。例えば、ヘッダファイルabc.hで定義した内容を利用するには、次のようにインクルードします。

  #include "abc.h"
  

条件コンパイル

 ヘッダファイルに書く内容(書いても良い内容)には、いくつか例外があります。例えば定数宣言がそうです。

  const float PI = 3.14159;
  

 円周率のような定数は広く使われるので、ヘッダファイルに含めたいところです。そのヘッダファイルをインクルードするだけでPIを定義できます。

 ところが、1つのプログラムで、2回以上同じ宣言をしてはいけません。すると、そのヘッダファイルは1つのプログラムで1回しかインクルードできません。

補足

 一般に1つのプログラムは、複数のファイル(*.cppファイル、*.hファイル)で構成されます。あるcppファイルが、ある定義を持つヘッダファイルをインクルードし、別のcppファイルが同じヘッダファイルをインクルードすると、同じ宣言を2回していることになってしまいます。

 そこで、#ifndefと#endifを使います。これらは、擬似命令と呼ばれるプリプロセッサによって処理される命令です。プリプロセッサとはコンパイルの前に実行されるコマンドのことです。プリプロセッサの実行は自動的に行われるので、通常、プログラマが意識する必要はありません。

 #ifndefと#endifの使い方は、これらの擬似命令でソースファイルの一部または全部を挟みます。

  
  #ifndef 記号定数
      .....
      .....
  
  #endif
  

 もし、指定した記号定数が定義されていなければ、これらの擬似命令は意味を持ちません。普通にコンパイルされます。しかし、もし記号定数が定義されていたなら、これらの擬似命令で挟まれた部分はコンパイルされません。

 つまり、#ifndefと#endif擬似命令を使用すると、条件によってコンパイルしたり、しなかったりを制御できます。これを条件コンパイルと呼びます。

重複定義の回避

 ヘッダファイルを作るとき、#ifndefと#endif、および記号定数を定義する#defineという擬似命令を使います。まず、ヘッダファイルの先頭に次の2行を入れます。

  
  #ifndef INCLUDED_Sample_h_
  
  #define INCLUDED_Sample_h_

 ここで指定したINCLUDED_Sample_h_は記号定数です。記号定数というのは、プリプロセッサだけが認識する名前です。ここで指定する記号定数の名前は何でもOKです。しかし、ヘッダファイルと同じ名前(この例ではヘッダファイル名がSample.h)にINCLUDED_を付けておけば、分かりやすいし、ほかの名前とダブらなくてすみます。

 そして、ヘッダファイルの最後に次の1行を入れます。

  
  #endif
  

 ヘッダファイルの名前がSample.hの場合なら次のようになります。

  
  #ifndef INCLUDED_Sample_h_
  
  #define INCLUDED_Sample_h_
  

const float PI = 3.14159;

#endif

 ヘッダファイルをこのように作ることによってどうなるのでしょうか? まず、そのプログラムで初めてSample.hがインクルードされたときを考えましょう。初めてのときは、まだINCLUDED_Sample_h_ は定義されていません。したがって、#ifndef は無視され、const float PI = 3.14159 がコンパイルされます。そして、#define により、記号定数INCLUDED_Sample_h_ が定義されます。

 2回目以降にSample.hがインクルードされると、すでにINCLUDED_Sample_h_ が定義されてます。このため、、#ifndef により、#define とconst float PI = 3.14159 が無視されます(コンパイルされない)。つまり、1つのプログラムでSample.h が何回かインクルードされても、定義は1回だけです。

 このように、ヘッダファイルに擬似命令を取り入れることにより、重複して定義される問題を回避することができます。