#directive) とマクロソースファイルに書き込む字句(トークン,Token)は,
のまとりとなります。この内,整数型や浮動小数点型の実数型,配列型,ポインタ型,構造体型,関数型の宣言,各種演算子と式,文,そして,関数の定義を見ました。ここでは「プリプロセッサ」について見ます。
前処理(プリプロセッシング,Preprocessing)とは,コンパイラがアセンブリ言語に翻訳する前に,ソースファイルの一部を条件的にスキップしたり,他のソースファイル(ヘッダファイル)を読み込んだり,マクロを置き換えるための処理で,「プリプロセッサ」(前処理指令,プリプロセッシング・ディレクティブ,Preprocessing Directive)はそのための命令を指します。
プリプロセッサは,字句要素の中の区切り子 # で始まり,改行で終わります。プリプロセッサで定義された定数や関数をマクロ(Macro)と呼びます。
| ■プリプロセッサ | |
#include <file> | 備え付けのヘッダファイル file の読み込み。/usr/include 内のファイル。 |
#include "myheader" | 自らが作成したヘッダファイル myheader の読み込み。 |
#if 条件 | if 文の始まり。#endif とペア。 |
#endif | if 文の終わり。#if とペア。 |
#else | if 文における分岐。 |
#elif 条件 | if 文における分岐。 |
#define マクロ | マクロ を定義。 |
#undef マクロ | #define マクロ で定義された マクロ を無効にする。 |
#ifdef マクロ | 「マクロ が定義されていれば」という意味。#if defined と同じ。 |
#ifndef マクロ | 「マクロ が定義されていなければ」という意味。#if !defined と同じ。 |
ヘッダファイルの読み込みについては,コンパイル時に I オプションを付してヘッダのあるディレクトリを追加することができます。
cc -I /path/to/directory1/ -I /path/to/directory2/ ...
この場合,自らが作成したヘッダファイルのあるディレクトリを追加すれば,#include "myheader" ではなく #include <myheader> としても,myheader を読み込めます。
/* Example 15.1 */
#include <stdio.h>
#include "def.h"
#ifndef PI
#define PI 3.14159
#endif
#ifndef E
#define E 2.71828
#endif
int main(void)
{
printf("PI = %f\n", PI);
printf("E = %f\n", E);
printf("max{PI,E} = %f\n", MAX(PI,E));
printf("min{PI,E} = %f\n", -MAX(-PI,-E));
return 0;
}
2つ目の #include で独自に作成したヘッダファイル def.h を読み込んでいます。その def.h のソースは次の通りです。
/* def.h */ #include <math.h> #define PI 4*atan(1.0) #define E exp(1.0) #define MAX(x,y) (x>y?x:y)
def.h の1つ目の #include でヘッダファイル math.h を読み込んでいます。ヘッダファイル math.h には,関数 exp や atan が入っています。最初の #define では円周率を意味するマクロ PI を 4*atan(1.0) と定義しています。2つ目の #define では,マクロ E を自然対数の底と定義しています。3つ目の #define では MAX というマクロを定義しています。2つの変数の最大値を出す関数です。def.h で定義された PI や E が定義されていない場合を想定して,元のソースファイルには #ifndef で再定義しています。実行結果は,次の通りです。
PI = 3.141593
E = 2.718282
max{PI,E} = 3.141593
min{PI,E} = 2.718282
def.h で定義された定数や関数は,正しく読み込まれているのが確認できます。(ソースを分割せずに,def.h の中身を元のソースの main 関数の上に入れ,#ifndef 部分を削除しても良いです。ここでは,例証のために分割しました。上のようなヘッダファイルの利用法とは別に,プログラムをモジュール化して行く段階で作成するヘッダファイルもあります。これについては「16. プログラムの分割とリンク」を参照して下さい。)
上では,PI や E,MAX というマクロを定義しましたが,マクロはコンパイラによって既に定義済みのものがあります。それらを変更することはできません。
| ■定義済みマクロ[C99, 6.10.8, 1の一部] | |
__LINE__ | 行番号。 |
__FILE__ | ソースファイル名。 |
__DATE__ | ソースファイルの変更日。mmm dd yyyy の形式で出力。 |
__TIME__ | ソースファイルの変更時間。hh:mm:ss の形式で出力。 |
__STDC__ | C99準拠のコンパイラならば 1 を出力。 |
/* Example 15.2 */
#include <stdio.h>
int main(void)
{
printf("LINE = %d\n", __LINE__);
printf("FILE = %s\n", __FILE__);
printf("DATE = %s\n", __DATE__);
printf("TIME = %s\n", __TIME__);
printf("STDC = %d\n", __STDC__);
return 0;
}
実行結果です。(機械に依存する部分があります。)
LINE = 7 FILE = ex15.2.c DATE = 09/24/02 TIME = 13:47:17 STDC = 1