C プリプロセッサ
C プリプロセッサ はコンパイラの一部ではありませんが、コンパイル プロセスの別のステップです。一言で言えば、C プリプロセッサは、実際のコンパイル前に必要な前処理を完了するようにコンパイラに指示するテキスト置換ツールにすぎません。 C プリプロセッサを CPP と略します。
すべてのプリプロセッサ コマンドはシャープ記号 (#) で始まります。これは最初の非 null 文字である必要があり、読みやすさを高めるために、プリプロセッサ ディレクティブは最初の列から開始する必要があります。すべての重要なプリプロセッサ ディレクティブを以下に示します。
ディレクティブ | 説明 |
---|---|
#define | define マクロ |
#include | ソース コード ファイルが含まれます |
#undef | キャンセル定義されたマクロ |
#ifdef | マクロがすでに定義されている場合はtrueを返します |
#ifndef | マクロが定義されていない場合はtrueを返します |
#if | if条件がtrueの場合をコンパイルし、次のコードをコンパイルします |
#else | #if 代替 |
#elif | 前の #if 与えられた条件が true ではなく、現在の条件が true の場合、次のコードをコンパイルします |
#endif | #if...#else 条件付きコンパイルブロックを終了します |
#error | 標準エラーが発生した場合、エラーメッセージを出力します |
#pragma | 正規化メソッドを使用して、コンパイラーはコンパイラーに特別なコマンドを発行します |
プリプロセッサの例
さまざまな命令を理解するために次の例を分析してください。
#define MAX_ARRAY_LENGTH 20
このコマンドは、CPP にすべての MAX_ARRAY_LENGTH を 20 に置き換えるよう指示します。 #define を使用して定数を定義し、可読性を高めます。
#include <stdio.h>#include "myheader.h"
これらの命令は、CPP に システム ライブラリ から stdio.h を取得し、現在のソース ファイルにテキストを追加するように指示します。次の行は、ローカル ディレクトリから myheader.h を取得し、その内容を現在のソース ファイルに追加するように CPP に指示します。
#undef FILE_SIZE#define FILE_SIZE 42
このコマンドは、定義された FILE_SIZE をキャンセルして 42 として定義するように CPP に指示します。
#ifndef MESSAGE #define MESSAGE "You wish!"#endif
このディレクティブは、MESSAGE が未定義の場合にのみ MESSAGE を定義するように CPP に指示します。
#ifdef DEBUG /* Your debugging statements here */#endif
このディレクティブは、DEBUG が定義されている場合に処理ステートメントを実行するように CPP に指示します。このディレクティブは、コンパイル時に -DDEBUG スイッチを gcc コンパイラに渡す場合に便利です。これは DEBUG を定義しており、コンパイル中にいつでもデバッグをオンまたはオフにできます。
定義済みマクロ
ANSI C では多くのマクロが定義されています。これらのマクロはプログラミングで使用できますが、事前定義されたマクロを直接変更することはできません。
マクロ | 説明 |
---|---|
__DATE__ | 現在の日付。「MMM DD YYYY」形式で表される文字定数。 |
__TIME__ | 現在時刻。「HH:MM:SS」の形式で表される文字定数。 |
__FILE__ | これには、現在のファイル名、文字列定数が含まれます。 |
__LINE__ | これには、現在の行番号 (10 進定数) が含まれます。 |
__STDC__ | コンパイラーが ANSI 標準にコンパイルする場合は 1 に定義されます。 |
次の例を試してみましょう:
#include <stdio.h>main(){ printf("File :%s\n", __FILE__ ); printf("Date :%s\n", __DATE__ ); printf("Time :%s\n", __TIME__ ); printf("Line :%d\n", __LINE__ ); printf("ANSI :%d\n", __STDC__ );}
上記のコード (ファイル test.c 内) がコンパイルされて実行されると、次の結果が生成されます:
File :test.cDate :Jun 2 2012Time :03:36:24Line :8ANSI :1
プリプロセッサ演算子
C プリプロセッサ プロセッサは、以下の演算子を提供します。マクロの作成に役立ちます:
マクロ継続演算子 ()
マクロは通常 1 行で記述されます。ただし、マクロが長すぎて 1 行に収まらない場合は、マクロ継続演算子 () を使用します。例:
#define message_for(a, b) \ printf(#a " and " #b ": We love you!\n")
文字列定数化演算子(#)
マクロ定義において、マクロパラメータを文字列定数に変換する必要がある場合、文字列定数化演算子(#)が使用されます。マクロで使用されるこの演算子には、特定の引数または引数リストがあります。例:
#include <stdio.h>#define message_for(a, b) \ printf(#a " and " #b ": We love you!\n")int main(void){ message_for(Carole, Debra); return 0;}
上記のコードをコンパイルして実行すると、次の結果が生成されます:
Carole and Debra: We love you!
タグ貼り付け演算子 (##)
マクロ定義内のタグ貼り付け演算子 (##) は、2 つのパラメーターをマージします。これにより、マクロ定義内で 2 つの独立したタグを 1 つのタグに結合できます。例:
#include <stdio.h>#define tokenpaster(n) printf ("token" #n " = %d", token##n)int main(void){ int token34 = 40; tokenpaster(34); return 0;}
上記のコードがコンパイルされて実行されると、次の結果が生成されます:
token34 = 40
これがどのように起こるかは、この例がコンパイラーから次の実際の出力を生成するためです:
printf ("token34 = %d", token34);
この例は token##n を示しています。は token34 に連結されます。ここでは、文字列定数化演算子 (#) と トークン貼り付け演算子 (##) を使用します。
define() 演算子
プリプロセッサ define 演算子は、#define を使用して識別子が定義されているかどうかを判断するために定数式で使用されます。指定された識別子が定義されている場合、値は true (ゼロ以外) です。指定された識別子が未定義の場合、値は false (ゼロ) になります。次の例は、define() 演算子の使用法を示しています。
#include <stdio.h>#if !defined (MESSAGE) #define MESSAGE "You wish!"#endifint main(void){ printf("Here is the message: %s\n", MESSAGE); return 0;}
上記のコードをコンパイルして実行すると、次の結果が生成されます:
Here is the message: You wish!
パラメータ化されたマクロ
CPP 強力な機能は、パラメータ化されたマクロを使用できることです。機能をシミュレートします。たとえば、次のコードは数値の 2 乗を計算します:
int square(int x) { return x * x;}
マクロを使用して上記のコードを次のように書き直すことができます:
#define square(x) ((x) * (x))
パラメーターを含むマクロを使用する前に、#define ディレクティブを使用してマクロを定義する必要があります。パラメータ リストは括弧で囲み、マクロ名の直後に続ける必要があります。マクロ名と開き括弧の間にスペースは使用できません。例:
#include <stdio.h>#define MAX(x,y) ((x) > (y) ? (x) : (y))int main(void){ printf("Max between 20 and 10 is %d\n", MAX(10, 20)); return 0;}
上記のコードをコンパイルして実行すると、次の結果が生成されます:
Max between 20 and 10 is 20