名前空間
変種
操作

翻訳フェーズ

From cppreference.com
< c‎ | language

Cソースファイルは、次のフェーズがこの厳密な順序で実行されるかのように、コンパイラによって処理されます。実際の], 実装では、動作が同じである限り、これらのアクションを組み合わせたり、異なる方法で処理したりする場合があります。

目次

[編集] フェーズ 1

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

[編集] フェーズ 2

1) バックスラッシュが行末(改行文字の直後)にある場合、バックスラッシュと改行の両方が削除され、2つの物理行が1つの論理行に結合されます。これは単一パス操作です。2つのバックスラッシュで終わり、その後に空行がある行は、3行を1つに結合しません。
#include <stdio.h>
 
#define PUTS p\
u\
t\
s
/* Line splicing is in phase 2 while macros
 * are tokenized in phase 3 and expanded in phase 4,
 * so the above is equivalent to #define PUTS puts
 */
 
int main(void)
{
 /* Use line splicing to call puts */ PUT\
S\
("Output ends here\\
0Not printed" /* After line splicing, the remaining backslash
               * escapes the 0, ending the string early.
               */
);
}
2) このステップの後(元々改行がなかったか、バックスラッシュで終わっていたかに関わらず)、空でないソースファイルが改行文字で終わっていない場合、動作は未定義です。

[編集] フェーズ 3

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

入力が指定された文字までプリプロセッサートークンに解析された場合、次のプリプロセッサートークンは、通常、プリプロセッサートークンを構成できる最長の文字シーケンスとして取得されます。これは、後続の分析が失敗する原因となる場合でも同様です。これは一般に*最大マッチャー*として知られています。

int foo = 1;
// int bar = 0xE+foo; // error: invalid preprocessing number 0xE+foo
int bar = 0xE/*Comment expands to a space*/+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; // error: bar++ ++ +baz, not bar++ + ++baz
int qux = bar+++/*Saving comment*/++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> is not a header-name

[編集] フェーズ 4

1) プリプロセッサが実行されます。
2) #include ディレクティブで導入された各ファイルは、再帰的にフェーズ1からフェーズ4まで処理されます。
3) このフェーズの終わりに、すべてのプリプロセッサディレクティブがソースから削除されます。

[編集] フェーズ 5

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

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

[編集] フェーズ 6

隣接する文字列リテラルが連結されます。

[編集] フェーズ 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++ドキュメント(*翻訳フェーズ*について)
English 日本語 中文(简体) 中文(繁體)