C で別のマクロに渡された引数で動作するマクロを定義するにはどうすればよいですか?

Linda Hamilton
リリース: 2024-11-15 15:02:03
オリジナル
578 人が閲覧しました

How to Define a Macro That Operates on Arguments Passed to Another Macro in C?

マクロ引数内のマクロ

問題

別のマクロに渡された引数を操作するマクロを定義するにはどうすればよいでしょうか?具体的には、次の点を考慮してください:

#define PRINT(a) printf(#a": %d", a)
#define PRINT_ALL(...) ? ? ? THE PROBLEM ? ? ? 
ログイン後にコピー

望ましい使用法:

int a = 1, b = 3, d = 0;
PRINT_ALL(a,b,d);
ログイン後にコピー

再帰の実現

型破りな回避策を使用すると、C で再帰マクロが可能になります。目標は、次のような MAP マクロを作成することです:

#define PRINT(a) printf(#a": %d", a)
MAP(PRINT, a, b, c) /* Apply PRINT to a, b, and c */
ログイン後にコピー

基本再帰

評価されないマクロ呼び出しに似たものを出力する方法を作成することから始めます:

#define MAP_OUT
ログイン後にコピー

次のマクロを検討します:

#define A(x) x B MAP_OUT (x)
#define B(x) x A MAP_OUT (x)
ログイン後にコピー

評価中A(何とか) はテキストを生成します:

blah B (blah)
ログイン後にコピー

B (何とか) 呼び出しはこの段階では単なるテキストであるため、プリプロセッサはここで再帰を検出しません。このテキストをプリプロセッサにフィードバックすると、それが展開されます。

blah blah A (blah)
ログイン後にコピー

この出力を再度評価すると、A (まあまあ) マクロが展開され、再帰が完了します。このプロセスは、出力が再びプリプロセッサにフィードバックされるまで続きます。

複数の評価を容易にするために、EVAL マクロを使用してマクロ呼び出しのチェーンに引数を渡します。

#define EVAL0(...) __VA_ARGS__
#define EVAL1(...) EVAL0 (EVAL0 (EVAL0 (__VA_ARGS__)))
#define EVAL2(...) EVAL1 (EVAL1 (EVAL1 (__VA_ARGS__)))
#define EVAL3(...) EVAL2 (EVAL2 (EVAL2 (__VA_ARGS__)))
#define EVAL4(...) EVAL3 (EVAL3 (EVAL3 (__VA_ARGS__)))
#define EVAL(...)  EVAL4 (EVAL4 (EVAL4 (__VA_ARGS__)))
ログイン後にコピー

Eachレベルは前任者の努力を増幅し、最終的に入力を 365 回評価します。たとえば、EVAL(A(何とか)) は、何とかの 365 コピーを生成し、その後に未評価の B (何とか) が続きます。このセットアップは、特定のスタック深さ制限内での再帰の基礎を提供します。

終了検出

次のハードルは、再帰をいつ終了するかを決定することです。

MAP_END マクロを次のように定義します。リストの終わりのマーカー:

#define MAP_END(...)
ログイン後にコピー

このマクロを評価しても何も行わず、

2 つのマクロのどちらかを選択するには、リスト項目を特別なリスト終了マーカー () と比較する MAP_NEXT を使用します。

#define MAP_GET_END() 0, MAP_END
#define MAP_NEXT0(item, next, ...) next MAP_OUT
#define MAP_NEXT1(item, next) MAP_NEXT0 (item, next, 0)
#define MAP_NEXT(item, next)  MAP_NEXT1 (MAP_GET_END item, next)
ログイン後にコピー

MAP_NEXT は、リスト項目と次の項目に基づいて続行または停止します。一致する場合は MAP_END を返し、そうでない場合は次のパラメータを返します。

すべてをまとめる

これらのコンポーネントを使用して、A と B の使用可能なバージョンを構築できます。

#define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
ログイン後にコピー

これらのマクロは、操作 f を現在のリスト項目 x に適用し、次のリスト項目であるピークを調べて、続行するかどうかを決定します。

最後に、トップレベルの MAP マクロですべてを組み立てます。

#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))
ログイン後にコピー

このマクロは、リストの最後に () マーカーを追加し、全体を EVAL に渡します。

コードは、便宜上、GitHub のライブラリとして利用できます。

以上がC で別のマクロに渡された引数で動作するマクロを定義するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート