3

サンプルプロジェクトでは、マクロを定義しました

#define FOO(x, y) x + y   .

これは完全にうまく機能します。たとえば、FOO(42, 1337)はに評価され1379ます。

しかし、私は今、別のものを使用したいと思います#define

#define SAMPLE 42, 1337

今電話するとFOO(SAMPLE)、これは機能しません。コンパイラーは、2つの引数を取ると言っていFOOますが、1つの引数でのみ呼び出されます。

これは、マクロの引数は関数自体に先立って評価されますが、プリプロセッサがこの評価後に命令全体を再度解析しないためだと思います。これは、マクロから追加のプリプロセッサディレクティブを出力できないという事実に似ています。

目的の機能を取得する可能性はありますか?

FOOマクロをC関数に置き換えることはできません。元のマクロは、変更できないサードパーティのコードにあり、配列初期化子で直接使用される値のコンマ区切りのリストを出力します。したがって、C関数は同じ動作を複製できません。

簡単な方法でこのタスクを実行できない場合:(x, y)ペアを保守可能な形式でどのように保存しますか?私の場合、8つの引数があります。したがって、個々のパーツを別々の#define-sに格納することも、保守が容易ではありません。

4

1 に答える 1

4

プリプロセッサがマクロを一致させず、必要な順序で展開しないという問題が発生しています。通常、追加のマクロを挿入して順序を正しくするように強制することで、必要なことを行うことができますが、そのためには、通常の順序が何であるかを理解する必要があります。

  • コンパイラは、引数の後に が続くマクロの名前を見つけると、(最初にその引数リストをスキャンし、引数内のマクロを認識または展開せずに引数に分割します。

  • #引数を解析して分離した後、マクロの各引数を再スキャンし、引数がマクロ本体と一緒に、または##マクロ本体で使用されていない限り、引数で見つかったものを展開します。

  • 次に、本体内の引数の各インスタンスを (現在は展開されている可能性がある) 引数に置き換えます。

  • 最後に、展開のために本文とともに存在する可能性のあるその他のマクロについて、本文を再スキャンします。この 1 回のスキャンでは、元のマクロは認識されず、再展開されないため、再帰的なマクロ展開はできません。

したがって、単一の引数を取り、それを展開する EXPAND マクロを慎重に使用することで、必要な効果を得ることができます。これにより、プロセスの適切な時点で追加の展開を強制できます。

#define EXPAND(X)   X
#define FOO(x,y)    x + y
#define SAMPLE      42, 1337

EXPAND(FOO EXPAND((SAMPLE)))

この場合、最初に引数リスト内のマクロを明示的に展開し、その後、結果のマクロ呼び出しを手動で展開します。

質問ポスターによる更新

#define INVOKE(macro, ...) macro(__VA_ARGS__)

INVOKE(FOO, SAMPLE)

EXPANDコードをsで乱雑にすることなく機能する拡張ソリューションを提供します。

于 2012-04-24T22:59:23.510 に答える