C言語のソースファイルから『実行可能ファイル』の作品が作られる過程は次の通りでした。
(step1) ソースファイルをコンパイルして、オブジェクトファイルを作成
(step2) オブジェクトファイルを結合して、『実行可能ファイル』を作成
この(1)のソースファイルをコンパイルする際、『ソースファイルに対して前処理』を行ってから、
それをコンパイルするようになっています。
この『ソースファイルに対する前処理 』を担当するプログラムはプリプロセッサと呼ばれます。
/* と */ のコメント範囲を削除して『余計なものがないC言語命令だけのデータ』に変換するのもプリプロセッサの仕事です。
このプリプロセッサに対する命令は、ソースの中で#から始まると決まっていて、
プリプロセッサ指示命令と呼ばれています。(C言語の命令ではなく、プリプロセッサ指示命令に属する)
つまり、これまで使っていたファイルを取り込む指示の#includeは、プリプロセッサ指示命令の一つなのです。
これにより、指定のインクルードファイルを埋め込んだものがコンパイルの対象になるわけです。
(なお、一般的にある処理の前処理をプリプロセスと呼びます)
#include <stdio.h> #include <stdlib.h>
#defineは、一般にマクロと呼ばれ、ソースファイル内の文字列置き換え指示です。
それは、ソースファイルで次のようにに書きます。
#define 置き換え対象の文字列 置き換え後の文字列
ソースファイルにおいて、この記述以降に置き換え対象の文字列の箇所があると、
その文字列は、置き換え後の文字列に置き換えられます。
以下に簡単な例を示します。
#include <stdio.h> #define SIZE 100 /* 配列の要素数 */ main() { int b[SIZE]; int i; /* 配列をアクセス添え字記憶用 */ for( i = 0; i < SIZE; i++ ) { b[i] = -1; } ... 以下省略 ...
口語的には、
『SIZEを100に定義する』
と言います。これで上記プログラムは、100個の要素の配列を作り、100回の繰り返しを行うプログラムとなります。
しかも、100の一箇所を変更するだけで、
サイズの異なるプログラムにできます。
なお、置き換え対象の文字列で大文字を使い、
置き換え後の文字列に
セミコロン『;』を付けない定義が一般的です。
仮に、上記で
#define SIZE 100;
とセミコロンを付けてしまうと、
int b[SIZE];
は、
int b[100;];
に置き換えら、よけいなセミコロンでコンパイルエラーになってしまいます。
次に極端に使った例を示します。
これは コードとしてはこの好ましくないのですが、
ソース内部のどんな文字列でも置き換え可能なことを示すものとして提示しています。
左が元のソースで、右がプリプロセッサによって出来上がるコンパイル対象のデータです。
元のソース(プリプロセス前) | プリプロセス後のコンパイル対象 |
---|---|
#define FORMAT "%d" /* scanf printf兼用 */ #define TRUE 1 #define START main(){ #define END } int scanf(char *, ...); /* プロトタイプ宣言 */ int printf(char *, ...); /* プロトタイプ宣言 */ START int data; /* 入力データ */ while( scanf(FORMAT , &data) == TRUE){ printf( FORMAT , data); } END |
int scanf(char *, ...); int printf(char *, ...); main(){ int data; while( scanf("%d" , &data) == 1){ printf( "%d" , data); } } |
右に示すプリプロセス後のコンパイル対象データは、コメントや#defineの記述がなくなります。
#includeを使いませんでしたが、使うとそのインクルードファイルの内容が埋め込まれたものになります。
なお、#define は、同じ置き換え対象の文字列を何回使っても構いません。使った位置の次の行から
が置き換え対象になります。