2013-08-27 13 views
19

私はcode golfを通じて見て、このコードしようとするアイデアを得てきた:この行を追加した後別のプリプロセッサディレクティブを定義することはできますか?

#define D #defineを、すべてのものは、しかし、私はこの中にそれを拡大し、うまく働いた:

#define D #define 
D VALUE 

をそしてここで私が得ました5コンパイルエラー。私がD#defineに変更すると、すべてが問題なく、誰かが説明できるのですが、なぜこのコードが違法ですか?

注:私はVS2008コンパイラを使用しました。

編集:私は、私はコンパイルにエラーリストを提供するために必要なことがわかりいくつかの答えの後

  1. エラーC2121:「#」:無効な文字:マクロ展開
  2. エラーC2146の可能性の結果:構文エラー: ';'がありません識別子 'VALUE'の前に
  3. エラーC4430:型指定子がない - 想定されています。注:C++はdefault-intをサポートしていません
  4. エラーC2144:構文エラー: 'void'の前に ';'を付けてください。
  5. エラーC4430:型指定子がありません - 想定されています。注:C++は、デフォルト-INT

まずエラーがDがちょうどdefineではありませんが、また#が含まれていることを示してサポートしていません。

+0

実装に依存することがありますので、使用しているコンパイラを明記してください。 –

+4

"なぜこのコードは違法ですか?" - プリプロセッサディレクティブを再定義することはできないためです。 –

+0

@ H2CO3初めてそれが働いたので私はそれを再定義できましたが、その定義の使用後にコンパイルエラーが発生しました。 – ST3

答えて

10

言語仕様に違法であると言われているため、このコードは不正です。 CおよびC++プリプロセッサ仕様によれば、プリプロセッサを使用して構築したコードは、決して別のプリプロセッサ指令として解釈されません。つまり、プリプロセッサを使用してプリプロセッサディレクティブを作成することはできません。期間。プリプロセッサの目にはコードの

(また、あなたはプリプロセッサを使用して、コメントを構築することはできません。)

11

プリプロセッサが必要とする置換を行っているように見えますが、通常はプリプロセッサは単なるパス操作です。 (打ち鳴らすと、しかし、あなたは適切なVS2008フラグを使用して再現することができるはずです)例:

$ cat example.c 
#define D #define 
D VALUE 
$ cc -P -E example.c 

#define VALUE 

#define VALUEはそれで何をすべきかわからないであろう、まっすぐにコンパイラに通過していること - それはです結局のところ、プリプロセッサ指令。クランのエラーは、参考のために、あなたのようになります。

$ cc -c example.c 
example.c:2:1: error: expected identifier or '(' 
D VALUE 
^ 
example.c:1:11: note: expanded from macro 'D' 
#define D #define 
     ^
1 error generated. 
+15

プリプロセッサがシングルパス演算であるかどうかは関係ありません。プリプロセッサは、個々の行を再処理するためにファイルのスキャンを複数回行う必要はありません。それぞれの行を必要なだけ何度も処理することができます。実際には、これをします:マクロ置換が繰り返し実行されます。プリプロセッサ指令がマクロ置換後に処理されないのは、言語標準がそうでないためです。 –

+0

うん、合意した。公式の規則について知らなかった。 –

6

前処理は、単一のパスで実行されるため、動作しないこと。たとえば、次のコードを検討:前処理した後

#define MYDEFINEWEIRD #define 

MYDEFINEWEIRD N 6 

int main() { 

    return 0; 
} 

を、あなたのコードは次のようになります:

#define N 6 
int main() { 

    return 0; 
} 

と "の#define" はCまたはC++の有効な構文ではありません。また、結果のプリプロセッサディレクティブは処理されないため、コード内の "N"マクロへの後続の参照は解決されません。

g ++/gccを使用してコマンドラインからプリプロセッサを2回呼び出すことができます。次のコードを考えてみよう。CPP):

#include <iostream> 

#define MYDEFINEWEIRD #define 
MYDEFINEWEIRD N 6 

using namespace std; 

int main() { 
    cout << N << endl; 
    return 0; 
} 

次に、あなたが行うことができます:

$ g++ -E define.cpp | g++ -o define -x c++ - && ./define 

と出力は以下となります。

6 
+2

"前処理はシングルパスで実行されます" - いいえ、実際はそうではありません - これはエラーではない**です**。 –

+2

@ H2CO3、私はこの答えの結果が正しいと思います。 –

+0

@EricPostpischilまあ、それは単一パス操作だと言えます。しかしそれはそうではありませんか? '#define FOO BAR'、' #define BAR 0'、そして 'return FOO;'私は 'return 0;に展開されます。 –

31

C 2011(N1570)6.10.3.4 3:「完全にマクロ置き換えましたプリプロセストークンシーケンスは、たとえ類似していても前処理ディレクティブとして処理されません... "

C++ 2010(N309 2)16.3.4 [cpp.rescan] 3はまったく同じテキストを持っています。

+2

これは正しい答えです。 C言語標準では、プログラムソースコードの翻訳方法の正確な操作順序が指定されています。 –

+1

"これは1に似ていても"この文章は1989年のANSI C標準(そしてその前のほとんどのドラフト)に戻ります。 – Kaz

+0

N3092は標準ではありませんが、間違いなくC++ 98、C++ 11、すべてのC++標準のドラフトでも同じですが – Potatoswatter

1

行はプリプロセッサ文(そしてこうして任意の置換がそれらに行われていない)、または通常のテキストのどちらかでありますステートメント(そして、置換が完了している)あなたは両方を持つことはできません。一度「D」を置き換えると、これ以上置き換えるマクロがあるかどうかを調べるだけです。存在しないので、そのままC++コードに '#define'を残しておき、C++コンパイラはそれを見るとエラーになります( '#define'は有効なC++コードではないため)。

だから私のポイントは、より多くの、これはプリプロセッサのための無効なコードであることを示す:

#define D define 
#D value 

プリプロセッサは、任意のマクロプリプロセッサ文の交換、および「#D」を行っていないので認識されたプリプロセッサコマンドではありません。そして、この:このC++コードでの

#define D #define 
D value 

結果:

#define value 

プリプロセッサがすでに実行されて行われるため、無効です。文法を見て

1

16 [CPP]段落1、生産を含んでいてもよいがPP-トークンから成る交換リスト#無指向同項のパラグラフ2に記載されていますas

非指示語は、リストに表示されている指示語名で始めることはできません。ある

は、フォーム

#define NAME # define 

の何かが違法であることを起こります!この文脈では#ではないことに注意してください。は次の単語を文字列に変換します。#に続く引用符は、すぐ後に機能スタイルのマクロでマクロパラメータ名が続きます。

+0

「非指令は開始してはいけません...」という文の中の '非指令'文法記号は、 '#non-directive'行を指します。したがって、 '#some-directive'のような行を'#non-directive'のような行から区別するだけです。これは、 '#define NAME#define'を無効なプリプロセッサトークンシーケンスにするものではありません。 –

関連する問題