8

私の知る限り、この質問はCとC ++に等しく適用されます

C標準 (ドラフト C99 標準の 5.1.1.2) で指定されている「変換フェーズ」のステップ 6では、隣接する文字列リテラルを単一のリテラルに連結する必要があると述べています。いえ

printf("helloworld.c" ": %d: Hello "
       "world\n", 10);

(構文的に) 以下と同等です。

printf("helloworld.c: %d: Hello world\n", 10);

ただし、標準では、コンパイラのどの部分がこれを処理する必要があるかを指定していないようです-プリプロセッサ( cpp)またはコンパイラ自体である必要があります。一部のオンライン調査によると、この機能は一般にプリプロセッサ (ソース #1ソース #2など) によって実行されることが期待されており、これは理にかなっています。

ただし、cppLinux で実行すると、それcppが行われないことが示されます。

eliben@eliben-desktop:~/test$ cat cpptest.c 
int a = 5;

"string 1" "string 2"
"string 3"

eliben@eliben-desktop:~/test$ cpp cpptest.c 
# 1 "cpptest.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "cpptest.c"
int a = 5;

"string 1" "string 2"
"string 3"

それで、私の質問は次のとおりです。言語のこの機能は、プリプロセッサまたはコンパイラ自体のどこで処理する必要がありますか?

おそらく、唯一の良い答えはありません。経験、既知のコンパイラ、および一般的な優れたエンジニアリング プラクティスに基づくヒューリスティックな回答を歓迎します。


PSなぜ私がこれを気にするのか疑問に思っているなら... PythonベースのCパーサーが文字列リテラルの連結を処理する必要があるか(現時点では処理しない)、またはどちらに任せるかを理解しようとしてcppいます。その前に実行されることを前提としています。

4

5 に答える 5

9

標準では、プリプロセッサとコンパイラを指定していません。既に指摘した変換のフェーズを指定しているだけです。従来、フェーズ 1 から 4 はプリプロセッサに、フェーズ 5 から 7 はコンパイラに、フェーズ 8 はリンカにありましたが、いずれも標準では要求されていません。

于 2010-06-29T16:27:07.557 に答える
4

プリプロセッサがこれを処理するように指定されていない限り、それはコンパイラの仕事であると想定しても安全です。

編集:

投稿の冒頭にある「Ie 」リンクは、次の質問に答えます。

隣接する文字列リテラルはコンパイル時に連結されます。これにより、長い文字列を複数の行に分割できます。また、C プリプロセッサの定義とマクロから生成された文字列リテラルをコンパイル時に文字列に追加することもできます...

于 2010-06-29T16:22:43.620 に答える
2

ANSI C 規格では、この詳細はセクション 5.1.1.2 の項目 (6) で説明されています。

5.1.1.2 変換フェーズ
...

4. 前処理ディレクティブが実行され、マクロ呼び出しが展開されます。...

5. 文字定数および文字列リテラル内の各ソース文字セット メンバーおよびエスケープ シーケンスは、実行文字セットのメンバーに変換されます。

6. 隣接する文字列リテラル トークンが連結され、隣接するワイド文字列リテラル トークンが連結されます。

標準では、実装でプリプロセッサとコンパイラを使用する必要があること自体は定義されていません。

ステップ 4 は明らかにプリプロセッサの責任です。

ステップ 5 では、「実行文字セット」がわかっている必要があります。この情報はコンパイラにも必要です。プリプロセッサにプラットフォームの依存関係が含まれていない場合は、コンパイラを新しいプラットフォームに移植する方が簡単です。そのため、ステップ 5、したがってステップ 6 をコンパイラに実装する傾向があります。

于 2010-06-29T16:29:57.983 に答える
1

文字列リテラルの連結がエスケープ シーケンスとどのように相互作用するかについては、注意が必要なルールがあります。あなたが持っていると仮定します

const char x1[] = "a\15" "4";
const char y1[] = "a\154";
const char x2[] = "a\r4";
const char y2[] = "al";

次にx1、 とx2によると等しくなる必要があり、 と についてもstrcmp同じです。(これは Heath が変換手順を引用する際に得ているものです。文字列定数の連結の前にエスケープ変換が行われます。) また、連結グループ内の文字列定数のいずれかにorプレフィックスがある場合は、ワイド文字列または Unicode 文字列を取得する必要があります。 . すべてをまとめると、この作業を「プリプロセッサ」ではなく「コンパイラ」の一部として行う方がはるかに便利です。 y1y2LU

于 2010-07-16T18:00:00.373 に答える
1

パーサーのスキャントークン部分で処理するので、コンパイラーで処理します。より論理的なようです。プリプロセッサは言語の「構造」を知る必要はありません。実際、マクロがコンパイルできないコードを生成できるように、通常はそれを無視します。それは、特にそれにアドレス指定されたディレクティブによって処理する権利があるもの(# ...)と、それらの「結果」(#define x hプリプロセッサが多くの x を h に変更するa のようなもの)を処理します。

于 2010-07-05T20:37:15.147 に答える