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 を使用して引数を取るマクロを定義できます:
Live Demo#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
プログラムをデバッグ目的でコンパイルできます。1つのマクロを使用してデバッグをオン/オフできます:
#ifdef DEBUG cerr << "Variable x = " << x << endl; #endif
これは、#ifdef DEBUG ディレクティブの前にシンボリック定数 DEBUG が定義されている場合、cerr 文がプログラムにコンパイルされることを意味します。#if 0 文を使用して、プログラムの一部をコメントアウトできます:
#if 0 コンパイルされないコード #endif
以下の例を試してみてください:
Live Demo#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;
}
上記コードをコンパイルして実行すると、以下の結果が得られます:
The minimum is 30 Trace: Inside main function Trace: Coming out of main function
# と ## 演算子
# と ## プリプロセッサ演算子はC++とANSI/ISO Cで利用可能です。# 演算子は、置換テキストトークンを引用符で囲まれた文字列に変換します。
以下のマクロ定義を考えてみてください:
Live Demo#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++" に置き換えられます。
Live Demo#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++には以下の定義済みマクロが用意されています:
| No. | マクロと説明 |
|---|---|
| 1 | __LINE__ プログラムがコンパイルされているときの現在の行番号を含む。 |
| 2 | __FILE__ プログラムがコンパイルされているときの現在のファイル名を含む。 |
| 3 | __DATE__ ソースファイルがオブジェクトコードに変換された日付を month/day/year 形式の文字列で含む。 |
| 4 | __TIME__ プログラムがコンパイルされた時刻を hour:minute:second 形式の文字列で含む。 |
上記すべてのマクロの例:
Live Demo#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
C言語
- C#プリプロセッサディレクティブ完全ガイド:条件付きコンパイルと診断制御
- C++データ型完全ガイド:基本型、修飾子、ベストプラクティス
- C++演算子完全ガイド:算術・代入・関係・論理・ビット演算子と実例
- C++コメント完全ガイド:読みやすく保守しやすいコードのためのベストプラクティス
- C++コンストラクタ完全ガイド:デフォルト、パラメータ付き、コピーの違いと実例
- C++クラステンプレート完全ガイド:実践的なジェネリックプログラミング
- C言語プリプロセッサ(CPP)の理解:コンパイルをシンプルにする仕組み
- C++プログラミング言語:概要と主要機能
- C++定数とリテラル完全解説:型、構文、ベストプラクティス
- C++演算子完全ガイド:種類、使い方、ベストプラクティス
- C++数値型完全ガイド:実践的な使い方と数学関数