C++ プリプロセッサ


プリプロセッサは、実際のコンパイルの前に実行する必要がある前処理についてコンパイラーに指示する命令です。

すべてのプリプロセッサ ディレクティブはポンド記号 (#) で始まり、プリプロセッサ ディレクティブの前に使用できるのはスペース文字のみです。前処理ディレクティブは C++ ステートメントではないため、セミコロン (;) で終わりません。

これまでのすべての例に #include ディレクティブがあることがわかりました。このマクロは、ヘッダー ファイルをソース ファイルにインクルードするために使用されます。

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

#define preprocessing

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

#define macro-name 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 <<"The minimum is " << MIN(i, j) << endl;

    return 0;
}

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

The minimum is 30

条件付きコンパイル

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

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

#ifndef 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 の両方で使用できます。 # 演算子は、置換テキスト トークンを引用符で囲まれた文字列に変換します。

以下のマクロ定義を参照してください:

#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__これには、ソースファイルがターゲットコードに変換された日付を表す月/日/年の形式の文字列が含まれます。
__TIME__これには、プログラムがコンパイルされた時刻を表す、時:分:秒の形式の文字列が含まれます。

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

#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