C++ プリプロセッサ

プリプロセッサは、実際のコンパイル前に実行すべき前処理をコンパイラに指示するディレクティブです。

すべてのプリプロセッサディレクティブはハッシュ記号(#)で始まり、プリプロセッサディレクティブの前には空白文字のみが置かれます。プリプロセッサディレクティブは C++ の文ではないため、セミコロン(;)で終わりません。

これまで見てきたように、これまでのすべての例には#includeディレクティブが含まれています。このマクロはヘッダーファイルをソースファイルにインクルードするために使われます。

C++ は、#include、#define、#if、#else、#line など、多くのプリプロセッサディレクティブもサポートしています。これらの重要なディレクティブを見てみましょう。

#define プリプロセッサ

#define プリプロセッサディレクティブは、記号定数を作成するために使用されます。この記号定数は通常宏マクロと呼ばれ、ディレクティブの一般的な形式は次のとおりです:

#define macro-name replacement-text 

このコード行がファイル内に現れると、そのファイル内で後続に現れるすべてのマクロは、プログラムのコンパイル前に replacement-text に置き換えられます。例:

#include <iostream> using namespace std; #define PI 3.14159 int main () { cout << "Value of PI :" << PI << endl; return 0; }

では、このコードをテストして、プリプロセスの結果を確認してみましょう。ソースコードファイルがすでに存在すると仮定し、次に -E オプションを使用してコンパイルし、結果を test.p にリダイレクトします。test.p ファイルを確認すると、大量の情報が含まれており、ファイルの下部の値が次のように変更されていることがわかります:

$ gcc -E test.cpp > test.p

...
int main ()
{
 
    cout << "Value of PI :" << 3.14159 << endl; 

    return 0;
}

パラメータ付きマクロ

#define を使用して、次のようにパラメータ付きマクロを定義できます:

#include <iostream> using namespace std; #define MIN(a,b) (a<b ? a : b) int main () { int i, j; i = 100; j = 30; cout <<"小さい方の値は:" << MIN(i, j) << endl; return 0; }

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

较小的值为:30

条件付きコンパイル

プログラムのソースコードの一部を選択的にコンパイルするために使用できるディレクティブがいくつかあります。このプロセスは条件付きコンパイルと呼ばれます。

条件付きプリプロセッサの構造は、if 選択構造と非常によく似ています。次のプリプロセッサコードを見てください:

#ifdef NULL
   #define NULL 0
#endif

デバッグ時のみコンパイルすることができます。デバッグスイッチは、次のようにマクロを使用して実装できます:

#ifdef DEBUG
   cerr <<"Variable x = " << x << endl;
#endif

ディレクティブ #ifdef DEBUG の前に記号定数 DEBUG が定義されている場合、プログラム内のcerr文がコンパイルされます。#if 0 文を使用して、プログラムの一部をコメントアウトできます。次のようにします:

#if 0
   不进行编译的代码
#endif

次の例を試してみましょう:

例

#include <iostream> using namespace std; #define DEBUG #define MIN(a,b) (((a)<(b)) ? a : b) int main () { int i, j; i = 100; j = 30; #ifdef DEBUG cerr <<"Trace: Inside main function" << endl; #endif #if 0 /*これはコメント部分です*/ cout << MKSTR(HELLO C++) << endl; #endif cout <<"The minimum is " << MIN(i, j) << endl; #ifdef DEBUG cerr <<"Trace: Coming out of main function" << endl; #endif return 0; }

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

Trace: Inside main function
The minimum is 30
Trace: Coming out of main function

# および ## 演算子

# および ## プリプロセッサ演算子は、C++ と ANSI/ISO C の両方で使用できます。# 演算子は replacement-text トークンを引用符で囲まれた文字列に変換します。

次のマクロ定義を見てください:

例

#include <iostream> using namespace std; #define MKSTR( x ) #x int main () { cout << MKSTR(HELLO C++) << endl; return 0; }

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

HELLO C++

どのように機能するか見てみましょう。理解しやすいように、C++ プリプロセッサは次の行を:

cout << MKSTR(HELLO C++) << endl;

次のように変換します:

cout << "HELLO C++" << endl;

## 演算子は2つのトークンを連結するために使用されます。次に例を示します:

#define CONCAT( x, y )  x ## y

CONCAT がプログラム内に現れると、そのパラメータが連結され、マクロを置き換えるために使用されます。例えば、プログラム内の CONCAT(HELLO, C++) は "HELLO C++" に置き換えられます。次の例のとおりです。

例

#include <iostream> using namespace std; #define concat(a, b) a ## b int main() { int xy = 100; cout << concat(x, y); return 0; }

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

100

どのように機能するか見てみましょう。理解しやすいように、C++ プリプロセッサは次の行を:

cout << concat(x, y);

次のように変換します:

cout << xy;

C++ の定義済みマクロ

C++ には、次の表に示すいくつかの定義済みマクロがあります:

宏 説明
__LINE__ これは、プログラムのコンパイル時に現在の行番号を含めます。
__FILE__ これは、プログラムのコンパイル時に現在のファイル名を含めます。
__DATE__ これは、ソースファイルをオブジェクトコードに変換した日付を表す month/day/year 形式の文字列を含めます。
__TIME__ これは、プログラムがコンパイルされた時刻を表す hour:minute:second 形式の文字列を含めます。

上記のマクロの例を見てみましょう:

例

#include <iostream> using namespace std; int main () { cout << "Value of __LINE__ : " << __LINE__ << endl; cout << "Value of __FILE__ : " << __FILE__ << endl; cout << "Value of __DATE__ : " << __DATE__ << endl; cout << "Value of __TIME__ : " << __TIME__ << endl; return 0; }

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48
その他の拡張