前処理(プリプロセス)
前処理 (preprocessing) ではコンパイルに先立ってソース・ファイルを様々に加工します。
注釈はコンパイルそのものには無関係であり邪魔者でもあるので、前処理によって半角空白一文字に置換されます。
その他コンパイラーがコンパイル作業をし易くする為の処理等を行うプログラムがプリプロセッサです。
翻訳フェーズ
C言語のコンパイルは、大きく分けて、「前処理(プリプロセス)」、「(狭義の)コンパイル」、
そして「リンク」の順に解決されます。
このような順序は、JIS X3010:2003 の中の「5.1.1.2 翻訳フェーズ」で規定されています。
翻訳フェーズの大まかな流れは以下のようになります。
-
物理変換(多バイト、改行、3文字表記)
ソースファイル中の物理的な文字を内部表現に置換する。改行コードや文字コードの置換もここで行われる。
処理系定義の多バイト文字 → 対応するソース文字集合
3 文字表記(trigraph sequence) → 対応する文字
※ gcc はデフォルトでは trigraph 禁止になっています
-
接合(逆斜線文字処理)
行末に逆斜線文字 \ があれば、物理ソース行を連結し、論理ソース行を生成する。
-
前処理字句・空白類文字整理
ソースファイルを前処理字句と空白類(注釈を含む)の並びに分解する。
注釈はひとつの空白文字に置換する。
-
前処理
前処理指令(プリプロセッサ・ディレクティブ)を実行する。
マクロ呼出しを展開する。
_Pragma 式を実行する。
#include 指令を展開し、取り込んだソースファイルに対して、1.~4.を再帰的に実行する。
すべての前処理指令を削除する。
-
実行文字集合置換
文字定数および文字列定数中の各要素を、対応する実行文字集合に置換する。
-
連結(文字列リテラル)
隣接する文字列リテラルを連結する。
-
翻訳
翻訳単位として翻訳する。
前処理字句 → 字句に変換する。
字句の構文および意味を解析する。
-
連係(オブジェクト、関数)
すべての外部オブジェクトおよび外部関数の参照を解決する。
その翻訳単位中に定義されていない関数およびオブジェクトへの外部参照を解決するため、 ライブラリの構成要素に連係する。
これらすべての翻訳出力をまとめて、実行環境上で実行に必要な情報を含む一つのプログラムイメージを作る。
ここで、1.~6.がいわゆる「前処理」、7.が「(狭義の)コンパイル」、そして8.がリンクに相当します。
前処理指令(プリプロセッサ・ディレクティブ)
前処理指令(preprocessing directive)とは、「#」前処理字句で始まり、それに続く最初の改行文字で終わる一連の前処理字句です。
前処理指令によって、 ソースファイルの一部分を条件によって処理したり読み飛ばしたり、
他のソースファイルを組み込んだり、 マクロを置き換えたりすることができます。
これらの処理は、概念的にはその翻訳単位の翻訳の前に行うので、前処理と呼びます。
前処理指令一覧
前処理指令 | 名称 | 概要 |
---|---|---|
#if | 条件付き取り込み (定数式指定) |
ソースファイルの一部分を条件によって処理したり読み飛ばしたりする |
#elif | 条件付き取り込み (別定数式指定) |
ソースファイルの一部分を条件によって処理したり読み飛ばしたりする |
#else | 条件付き取り込み (条件外) |
ソースファイルの一部分を条件によって処理したり読み飛ばしたりする |
#ifdef | 条件付き取り込み (識別子真判定) |
ソースファイルの一部分を条件によって処理したり読み飛ばしたりする |
#ifndef | 条件付き取り込み (識別子否判定) |
ソースファイルの一部分を条件によって処理したり読み飛ばしたりする |
#endif | 条件付き取り込み (条件終了) |
#if、#ifdef、#ifndefを終了する |
#pragma | プラグマ指令 | 処理系に対し処理系定義の方法で動作することを指示する |
#include | ソースファイル取り込み | 他のソースファイルを取り込む |
#define | マクロ置き換え | マクロ名を置換要素並びで置き換える |
#undef | マクロ削除 | マクロを削除、未定義にする命令 |
#assert | 表明 | プログラム中に診断機能を付け加える |
#line | 行制御 | 行制御とは、この指令の次のソース行の行番号を指定する |
#error | エラー指令 | エラー指令とは、処理系に対し、 指定された前処理字句の列を含む診断メッセージを出力することを指示する |
# | 空指令 | 空指令とは、何の効果もない前処理指令 |