8

私はこのコードを少し持っています (実際には、ガベージコレクションされた Forth システムのインタープリターの一部です):

#define PRIMITIVE(name) \
    do \
    { \
        VocabEntry* entry = (VocabEntry*)gc_alloc(sizeof(VocabEntry)); \
        entry->code = name; \
        entry->name = cstr_to_pstr(#name); \
        entry->prev = latest_vocab_entry; \
        latest_vocab_entry = entry; \
    } \ 
    while (false)

PRIMITIVE(dup);
PRIMITIVE(drop);
PRIMITIVE(swap);
// and a lot more

しかし、問題があります: 行に

entry->name = cstr_to_pstr(#name);

フィールドは、、、、およびその他にname置き換えられます。フィールド名を代入しないでほしい。dupdropswap

それで、単にマクロ引数の名前を変更する以外に、これを解決する方法はありますか?

回答として、一般に、マクロ本体でマクロ引数名の置換を抑制する方法があるかどうかを説明してください。「このようにしてください」と答えないでください(お願いします)。

4

3 に答える 3

17

name次のように、展開する別のマクロを定義できます。

#define Name name

次のように、新しいマクロを使用するようにマクロのnameフィールドを変更します。PRIMITIVE

#define PRIMITIVE(name) \
    do \
    { \
        VocabEntry* entry = (VocabEntry*)gc_alloc(sizeof(VocabEntry)); \
        entry->code = name; \
        entry->Name = cstr_to_pstr(#name); \
        entry->prev = latest_vocab_entry; \
        latest_vocab_entry = entry; \
    } \ 
    while (false)

マクロ本体でパラメータ名とは異なるものを使用するか、パラメータ名を変更する以外に、C 言語でこれを行う方法はありません。C 2011 (N1570) 6.10.3.1 1 によると、関数のようなマクロが認識されると、#or##が存在する場合を除いてパラメーター名がすぐに置き換えられ、他の例外はありません。

関数のようなマクロを呼び出すための引数が識別された後、引数置換が行われます。# または ## 前処理トークンが先行するか、## 前処理トークンが後続しない限り (以下を参照)、置換リスト内のパラメーターは、そこに含まれるすべてのマクロが展開された後に、対応する引数に置き換えられます。

#トークンはパラメーター名を文字列に変更しますが、これはこの状況では役に立ちません。トークンは##パラメーター名を展開し、隣接するトークンと一緒に貼り付けますが、これもこの状況では役に立ちません。

于 2013-08-11T02:35:57.043 に答える
5

いいえ、ありません。

その理由を理解するには、マクロ展開が実際にどのように行われるかを考える必要があります。関数のようなマクロを展開するには、次の 3 つの主な手順が必要です。

  1. #マクロがor演算子を使用しない限り、マクロへの引数は完全に展開さ##れます (これらは単一のトークンであるため、この例では関係ありません)。
  2. 置換リスト全体がスキャンされ、出現するパラメータ名が対応する引数に置き換えられます
  3. ステップ 2 が完了すると、展開された置換リスト自体が再スキャンされ、この時点で表示されるすべてのマクロが展開されます。

これは、標準セクション 6.10.3 (C11 および C99) で概説されています。

nameこれの結論は、「##」などの抑制ルールを取り、悪用できるある種のマクロを書くことは不可能であるというPRIMITIVE ことです.体内で自分の順番を認識できるようにします。置換リスト内のトークンに抑制のマークを付けるためにできることは何もありません。これは、置換ステップが既に実行された後にのみ、トークンに付けることができるマークが検査されるためです。順序は標準で指定されているため、この方法でトークンをマークできるエクスプロイトを見つけた場合は、コンパイラのバグです。

マクロ引数の名前を変更しないことに本当に設定されている場合は、連結マクロに個別の引数として渡すことnaをお勧めします。meトークンnameは、置換が行われた後にのみ形成され、リストはパラメーター名について検査されなくなります。

編集して、もっと速く入力したいです。

于 2013-08-11T02:41:21.390 に答える
1

いいえ、マクロの本体内で、マクロに宣言された引数のトークンと同一のトークンの置換を抑制する方法はありません。プリプロセッサコードにジャンプしない限り、考えられるすべての解決策では、引数名またはフィールド名のいずれかの名前を変更する必要があります(Ericの回答のように、そのマクロの目的のためだけに可能性があります)。

于 2013-08-11T02:35:46.723 に答える