Namespaces
Variants

Phases of translation

From cppreference.net

Cソースファイルは、以下のフェーズがこの正確な順序で行われるもの として コンパイラによって処理されます。実際の実装では、動作が同じである限り、これらのアクションを結合したり異なる方法で処理したりする場合があります。

目次

フェーズ1

1) ソースコードファイル(通常はUTF-8などのマルチバイトエンコーディングのテキストファイル)の個々のバイトは、実装定義の方法で source character set の文字にマッピングされます。特に、OS依存の行末指示子は改行文字で置き換えられます。
source character set はマルチバイト文字セットであり、以下の96文字からなる basic source character set を単一バイトのサブセットとして含みます:
a) 5つの空白文字(スペース、水平タブ、垂直タブ、フォームフィード、改行)
b) '0' から '9' までの10桁の数字文字
c) 52文字( 'a' から 'z' まで、および 'A' から 'Z' まで)
d) 29の句読点文字: _ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " '
2) トライグラフシーケンス は対応する単一文字表現で置き換えられます。 (C23まで)

Phase 2

1) バックスラッシュが行末に現れる場合(直後に改行文字が続く)、バックスラッシュと改行の両方が削除され、2つの物理ソース行が1つの論理ソース行に結合されます。これは単一パス操作です:2つのバックスラッシュで終わりその後に空行が続く行は、3行を1行に結合しません。
#include <stdio.h>
#define PUTS p\
u\
t\
s
/* 行の結合はフェーズ2で行われ、マクロは
 * フェーズ3でトークン化され、フェーズ4で展開されるため、
 * 上記は #define PUTS puts と等価です
 */
int main(void)
{
 /* 行の結合を使用して puts を呼び出す */ PUT\
S\
("Output ends here\\
0Not printed" /* 行の結合後、残ったバックスラッシュは
               * 0をエスケープし、文字列を早期に終了させる
               */
);
}
2) 空でないソースファイルがこのステップの後(元々改行がなかったか、バックスラッシュで終了していたかに関わらず)改行文字で終了しない場合、動作は未定義です。

フェーズ3

1) ソースファイルは、 comment 、空白文字(スペース、水平タブ、改行、垂直タブ、フォームフィード)の連続、および以下の preprocessing tokens に分解されます。
a) ヘッダー名: < stdio. h > または "myfile.h"
c) プリプロセス数。これには 整数定数 および 浮動小数点定数 が含まれるが、 1 .. E + 3. foo 0JBK のような無効なトークンも含まれる。
e) 演算子および区切り文字、例えば + <<= < % 、または ## など。
f) 他のカテゴリに適合しない個々の非空白文字
2) 各コメントは1つのスペース文字に置換されます
3) 改行は保持され、非改行空白シーケンスが単一のスペース文字に折り畳まれるかどうかは実装定義である。

入力が特定の文字まで前処理トークンに解析されている場合、次の前処理トークンは、その後の解析が失敗する場合でも、前処理トークンを構成できる文字の最長シーケンスとして一般に取得されます。これは一般に maximal munch として知られています。

int foo = 1;
// int bar = 0xE+foo; // エラー: 無効なプリプロセス番号 0xE+foo
int bar = 0xE/*コメントは空白に展開される*/+foo; // OK: 0xE + foo
int baz = 0xE + foo; // OK: 0xE + foo
int pub = bar+++baz; // OK: bar++ + baz
int ham = bar++-++baz; // OK: bar++ - ++baz
// int qux = bar+++++baz; // エラー: bar++ ++ +baz, bar++ + ++bazではない
int qux = bar+++/*区切りコメント*/++baz; // OK: bar++ + ++baz

最大マンチ規則の唯一の例外は次のとおりです:

  • ヘッダー名の前処理トークンは、 #include ディレクティブ内、 または #embed (C23以降) ディレクティブ内、 __has_include および __has_embed 式内 (C23以降) および #pragma ディレクティブ内の実装定義の場所でのみ形成されます。
#define MACRO_1 1
#define MACRO_2 2
#define MACRO_3 3
#define MACRO_EXPR (MACRO_1 <MACRO_2> MACRO_3) // OK: <MACRO_2> はヘッダー名ではない

フェーズ4

1) Preprocessor が実行されます。
2) #include ディレクティブで導入される各ファイルは、1から4までのフェーズを再帰的に通過します。
3) このフェーズの終了時点で、すべてのプリプロセッサディレクティブがソースから削除されます。

フェーズ 5

1) すべての文字と エスケープシーケンス は、 文字定数 および 文字列リテラル 内で ソース文字セット から 実行文字セット へ変換されます(これは、フェーズ1でリストされている 基本ソース文字セット の96文字すべてが単一バイト表現を持つ限り、UTF-8などのマルチバイト文字セットでもかまいません)。エスケープシーケンスによって指定された文字が実行文字セットのメンバーでない場合、結果は実装定義ですが、null(ワイド)文字ではないことが保証されます。

注: この段階で実行される変換は、一部の実装ではコマンドラインオプションで制御可能です: gccとclangは - finput - charset でソース文字セットのエンコーディングを指定し、 - fexec - charset および - fwide - exec - charset で文字列リテラルと文字定数における実行文字セットのエンコーディングを指定します (エンコーディングプレフィックスを持たないもの) (C11以降)

フェーズ6

隣接する string literals は連結されます。

フェーズ7

コンパイルが実行されます: トークンは構文的および意味的に解析され、翻訳単位として変換されます。

フェーズ 8

リンクが行われる: 外部参照を満たすために必要な翻訳単位とライブラリコンポーネントがプログラムイメージに収集され、その実行環境(OS)での実行に必要な情報が含まれます。

参考文献

  • C23規格 (ISO/IEC 9899:2024):
  • 5.1.1.2 翻訳段階 (p: TBD)
  • 5.2.1 文字集合 (p: TBD)
  • 6.4 字句要素 (p: TBD)
  • C17規格 (ISO/IEC 9899:2018):
  • 5.1.1.2 翻訳段階 (p: 9-10)
  • 5.2.1 文字集合 (p: 17)
  • 6.4 字句要素 (p: 41-54)
  • C11規格 (ISO/IEC 9899:2011):
  • 5.1.1.2 翻訳段階 (p: 10-11)
  • 5.2.1 文字集合 (p: 22-24)
  • 6.4 字句要素 (p: 57-75)
  • C99規格 (ISO/IEC 9899:1999):
  • 5.1.1.2 翻訳段階 (p: 9-10)
  • 5.2.1 文字集合 (p: 17-19)
  • 6.4 字句要素 (p: 49-66)
  • C89/C90標準 (ISO/IEC 9899:1990):
  • 2.1.1.2 翻訳段階
  • 2.2.1 文字集合
  • 3.1 字句要素

関連項目

C++ documentation for Phases of translation