第14回
ヘッダファイルとプリプロセッサ指令

主なプリプロセッサ指令

主要なヘッダファイル※2 は、#で始まるプリプロセッサ指令の集合』であると言えます。主なプリプロセッサ指令を紹介しておきましょう。

Cの処理系に予め準備されているヘッダファイルは確かにプリプロセッサ指令の集合となっています。 しかしCでは、プログラマーが独自の関数などを定義し、それを使うためのヘッダファイルを作ることがあります。 その場合、プリプロセッサ指令を記述しないこともあり得ます。

#include

機能 :
ファイルを取り込む
書式 :
#include <ファイル名>
詳細 :
<ファイル名>で示されたファイルを取り込みます。ファイル名を<>で囲むと、設定ファイルなどで予め指定された、処理系のヘッダファイルを保存しているディレクトリ(フォルダ)からファイルを探します。それ以外の場所にあるファイルを取り込みたい場合には、ファイル名を""で囲みます。

ファイル名を""で囲んだ場合、通常はファイルのフルパスを記述します。パスを省略してファイル名だけを記述すると、現在処理しているソースファイルと同じディレクトリからファイルを探します。

#define

機能 :
文字列の置き換え
書式 :
#define <文字列1> <文字列2>
詳細 :
識別子<文字列1>を値<文字列2>と定義します。先に“<識別子名> <値>”という書式を紹介しましたが、実際には#defineは文字列同士の置き換えを行っています。なぜなら、プリプロセッサ指令はあくまでソースファイルに記述された文字列(ソースコード)を扱っているに過ぎないからです。
#define __MAX 100
とすれば、コンパイルの段階では"__MAX"という記号が整数(int型)の100に置き換えられますが、ソースコード上では文字列の"__MAX"が"100"という文字列に置き換えられています。

プリプロセッサ指令は、あくまでも『文字の集合であるソースコード上で機能する命令』です。

#undef

機能 :
#defineによる文字列置き換えの取り消し
書式 :
#undef <識別子名>
機能 :
#defineで定義された識別子と値の置き換えを無効にします。この指令以降、<識別子名>の値は未定義を示す0になります。

#ifdef

機能 :
識別子が定義されているかどうかの判定
書式 :
#ifdef <識別子名>
<処理>
詳細 :
<識別子名>が定義済みなら<処理>を実行します。<処理>はプリプロセッサに対する指令です。識別子は#defineで値を定義しますが、未定義の場合は0となっています。従って#define指令では、識別子を0以外の値に定義する必要があります。
<処理>が複数行にわたる場合は、処理ブロックの最後を示すために#endifを記述します。

#ifndef

機能 :
識別子が定義されていないかどうかの判定
書式 :
#ifndef <識別子名>
<処理>
詳細 :
<識別子名>が未定義なら<処理>を実行します。
<処理>が複数行にわたる場合は、処理ブロックの最後を示すために#endifを記述します。

#endif

機能 :
#ifdef、#ifndefなどによる処理ブロックの最後を明示
詳細 :
#ifdef、#ifndef共に結果が「真」なら続く<処理>を1行実行します。複数行の処理を実行させたい場合は、その最後に#endifを記述してブロックの終端を示します。処理の構造を分かりやすくするため、1行の処理の最後に#endifを記述しても構いません。

プリプロセッサの制御構造

ある識別子が定義されているかどうか、または定義されていないかどうかは、上述の#ifdefと#ifndefで判別して処理を分岐できます。しかし、もっと複雑な判定を必要とする場合もあります。

例えば、
識別子Xが定義されていれば続けて別の識別子Yを定義し
そうでなく識別子Yが定義されていれば識別子Xを定義し
そうでなければ識別子Xと識別子Yを定義せよ
といった場合です。

そのような場合には、
#if~#elif~#else~#endif
という構造を使います。意味は一般的なCの構文にあるif~else if~elseと同じですが、ブロックの最後に#endifを記述する必要があります。

#ifによる値の判定

#ifには、続けて識別子が定義済みである(≠0)ことを示す“defined”や、『その識別子が特定の値であるかどうか』を判定するために識別子と値とを続けて記述する書式が使えます。

definedでは、続く()内に識別子を記述します。リスト2は
記号定数__MAXが定義されていれば記号定数__MINを10と定義
そうでなく記号定数__MINが定義されていれば
 記号定数__MAXを100と定義し
そうでなければ記号定数__MAXと__MINの両方を定義せよ
という処理を行います。

また
#if __MAX < 100
  #define __MAX 100
あるいは
#if __MAX == 10
  #define __MAX 100
のように#ifに続けて識別子と値とを比較演算子でつなぎ、「ある識別子がある値であれば……」「ある値以下なら……」といった条件判定の構造を作ることもできます。

リスト2:#if~#elif~#elseを使った記号定数の定義
#if defined(__MAX)
  #define __MIN 10
#elif defined(__MIN)
  #define __MAX 100
#else
  #define __MAX 100
  #define __MIN 10
#endif