10

Cプリプロセッサをいじっていたところ、非常に単純に見えたものが失敗しました。

#define STR_START "
#define STR_END "

int puts(const char *);

int main() {
    puts(STR_START hello world STR_END);
}

gcc でコンパイルすると (注意: clang で同様のエラーが発生します)、次のエラーで失敗します。

$ gcc test.c
test.c:1:19: 警告: 終端 " 文字がありません
test.c:2:17: 警告: 終端 " 文字がありません
test.c: 関数 'main' 内:
test.c:7: エラー: 終端 " 文字がありません
test.c:7: エラー: 'hello' が宣言されていません (この関数で最初に使用)
test.c:7: エラー: (宣言されていない識別子はそれぞれ一度だけ報告されます
test.c:7: エラー: 各関数に表示されます。)
test.c:7: エラー: 'world' の前に ')' が必要です
test.c:7: エラー: 終端 " 文字がありません

これは私を混乱させたので、プリプロセッサを介して実行しました:

$ gcc -E test.c
#1 「test.c」
#1「」
#1「」
#1 「test.c」
test.c:1:19: 警告: 終端 " 文字がありません
test.c:2:17: 警告: 終端 " 文字がありません

int puts(const char *);

int main() {
    puts("こんにちは世界");
}

警告にもかかわらず、これは完全に有効なコード (太字のテキスト) を生成します!

Cのマクロが単なるテキストの置換である場合、最初の例が失敗するのはなぜですか? これはコンパイラのバグですか? そうでない場合、標準のどこにこのシナリオに関する情報がありますか?

注:最初のスニペットをコンパイルする方法を探しているわけではありません。このシナリオが失敗する理由に関する情報を探しているだけです。

4

3 に答える 3

10

問題は、コードが に展開されても、プリプロセッサによって" hello, world "単一の文字列リテラルトークンとして認識されないことです。代わりに、(無効な)トークン, , , ,のシーケンスとして認識されています。 "hello,world"

N1570 :

6.4 語彙要素
...
3トークンは、翻訳フェーズ 7 および 8 における言語の最小の語彙要素です。トークンのカテゴリは、キーワード、識別子、定数、文字列リテラル、句読点です。前処理トークンは、翻訳フェーズ 3 から 6 における言語の最小字句要素です。前処理トークンのカテゴリは、ヘッダー名、識別子、前処理番号、文字定数、文字列リテラル、句読点、単一の非空白文字です。他の前処理トークン カテゴリと語彙的に一致しません。69) または文字が最後のカテゴリに一致する場合、動作は未定義です'". 前処理トークンは空白で区切ることができます。これは、コメント (後述) または空白文字 (スペース、水平タブ、改行、垂直タブ、フォームフィード)、またはその両方で構成されます。6.10 で説明されているように、変換フェーズ 4 の特定の状況では、空白 (またはその不在) は、トークン分離の前処理以上の役割を果たします。空白は、ヘッダー名の一部として、または文字定数または文字列リテラルの引用符の間にのみ前処理トークン内に表示される場合があります。
69) 追加のカテゴリであるプレースマーカーは、翻訳フェーズ 4 で内部的に使用されます (6.10.3.3 を参照)。ソース ファイルでは発生しません。

この定義では句読点 'も句読点でもないことに注意してください。"

于 2013-05-28T18:52:25.743 に答える
8

プリプロセッサは複数のフェーズで実行されます。フェーズ 3 のトークン化は展開の前に行われるため、プリプロセッサ マクロは完全なトークンを表す必要があります。あなたの場合、STR_STARTトークンSTR_END化されてから置換されるため、これらのトークンは無効になります。

于 2013-05-28T18:57:24.443 に答える
0

ここ

#define STR_START "

コンパイラは文字列リテラルを期待しています。文字列リテラルは、終了引用符で終了する必要があります。"そのため、コンパイラは終了文字が欠落していると不平を言います。

無効なトークンのため、マクロ展開コンパイラーが再び文句を言います。


たとえば、MSVC コンパイラは次のように文句を言います。

error C2001: newline in constant

展開後、引用符の欠落について不平を言います。

于 2013-05-28T20:20:16.020 に答える