5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C/C++間での翻訳フェーズの違い

Last updated at Posted at 2019-12-13

カレンダーが開いていたので、穴埋めがてら参加させていただきました

この記事は、C++ Advent Calendar 2019 の記事です

前日の記事は@tyu_ru_cppさんの「min/maxみたいな関数の呼び出し」でした
次日の記事は@RIO18020さんです

※翻訳フェーズ3のソース例とコメントを一部修正(12/14)

#はじめに
「そういやよく知らねえな…」とエッグマフィン食べながら思ったのでまとめ

翻訳フェーズ(translation phases)とは

ソースファイルの翻訳手順の事です。
C/C++両者とも規格上部にあるので探す手間が省けます。やったね。
(Cの場合「5.1.1.2」、 C++の場合「5.2」に記載されています)

ざっくり書き出すと以下の手順になっています

手順(ざっくり)

  1. ソースファイル上文字をソース文字集合に変換

  2. 行末のバックスラッシュと改行の2セットを削除

  3. ソースファイルを「プリプロセッシングトークン」,「コメント」,「空白類文字」の並びに分割し、コメントを1つの空白に置き換える

  4. プリプロセッサを実行

  5. 文字、文字列リテラル内の文字をソース文字集合→実行文字集合へ変換し、エスケープシーケンスを処理

  6. 隣接する文字列リテラルを結合

  7. コンパイルを実行

  8. [C++のみ]テンプレートの実体化

  9. 外部参照の解決

※補足(文字集合について)
ソース文字集合(source character set) …ソースコード上で用いられる文字セットの事。
最低限定義する必要のある「基本ソース文字集合」と、処理系が任意に定義する「拡張ソース文字集合」 がある

実行文字集合(execution character set) …実行時に用いられる文字セットの事。
ソース文字集合同様に「基本実行文字集合」 と「拡張実行文字集合」 がある

詳しくは各サイトや規格書を参照

C/C++での違い

基本的には同じ流れですが、C++で一部追加/変更された動作があります

1. ソースファイルの物理的な文字をソース文字集合に変換

C の場合、マルチバイト文字もソース文字集合へマッピングしますが
C++ の場合、基本ソース文字集合のみマッピングを行い、マッピング不可能な物は全てユニバーサル文字名へ置き換えられます

int main(void){
	int あああ = 10; // Cの場合変換先は処理系定義だが、C++の場合ユニバーサル文字名(\uXXXX)に置き換わる
}

この他C++17以降ではトライグラフの扱いが削除されていますが、
C++erのお方々がわざわざ知らなくても良いとおっしゃられていたのでスルー

2. 行末にあるバックスラッシュと改行の2セットを削除

この処理後のソースファイルが改行文字で終わらなかった場合
C&C++11以前 の場合、未定義動作となりますが
C++11以降 の場合、ファイル終端へ自動的に改行文字追加されます

int main(void)
{
	
}	// ファイル終端が改行文字で終了しなくなった時どうなるか
\

3. ソースファイルを「プリプロセッシングトークン」,「コメント」,「空白類文字」の並びに分割し、コメントを1つの空白に置き換える

C++11以降 の場合、加えてこのタイミングで生文字リテラル内のみフェーズ1~2までの変換作業が取り消されます

#include <cstdio>
int main(void){
	// バックスラッシュと行末の削除が取り消され、そのままとなる
	std::puts(R"(ほげほげ\
	\
	)");
}

4.プリプロセッサを実行

特に変わり無し

5. 文字、文字列リテラル内の文字をソース文字集合→実行文字集合へ変換し、エスケープシーケンスを処理

C++ の場合、ユニバーサル文字名の実行文字集合への展開が記載されています
またC++11以降 の場合、生文字リテラルにはエスケープシーケンス処理が適用されません

#ifndef __cplusplus
#define R
#endif

int main(void){
	const char * str = "あああ"; //Cの場合処理系定義の展開、C++の場合ユニバーサル文字名の展開として実行
	const char * str2 = R"(\nあああ\n)"; //生文字リテラルは対象外(基本ソース文字集合→実行文字集合への変換は行われる)
}

6. 隣接する文字列リテラルを結合

変わりなし

7. コンパイルを実行

C++20以降 の場合、実装定義でmoduleによる依存関係があるソース/ヘッダファイルが利用可能状態である必要が有る可能性があります。

8. [C++のみ]テンプレートの実体化

Cコンパイラはいくらお願いしてもやってくれません

9. 外部参照の解決

変わりなし

おわりに

「まあそうだよね」と言う違いが大半でした。
誤り、マサカリ等ございましたらよろしくお願いいたします。

参考

C++ Draft
C17 最終ドラフト
JIS C規格
cppreference.com(翻訳フェーズ)

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?