C で再帰マクロを実装するにはどうすればよいですか?

Barbara Streisand
リリース: 2024-11-17 19:49:02
オリジナル
134 人が閲覧しました

How Can We Implement Recursive Macros in C?

マクロ引数のマクロ再帰を理解する

C プログラミングでは、マクロはテキスト操作のための強力なツールを提供します。興味深い点の 1 つは、他のマクロの引数に対してマクロを使用できることです。ただし、この言語では再帰マクロが一般に許可されていないため、これには技術的な課題が伴います。

問題: 再帰マクロ

作成したいシナリオを考えてみましょう。 PRINT_ALL という名前の foreach マクロ。指定されたマクロ PRINT を引数のリストに適用します。例:

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

これは、変数 a、b、d のそれぞれに対して PRINT マクロを呼び出します。単純なアプローチでは、次のような再帰マクロを使用する可能性があります:

#define FIRST_ARG(arg,...) arg
#define AFTER_FIRST_ARG(arg,...) , ##__VA_ARGS__
#define PRINT(a) printf(#a": %d", a)
#define PRINT_ALL PRINT(FIRST_ARG(__VA_ARGS__)); PRINT_ALL(AFTER_FIRST_ARG(__VA_ARGS__))
ログイン後にコピー

ただし、このアプローチには 2 つの問題があります。マクロは自分自身を再帰的に呼び出すことができず、再帰を停止するための停止条件がありません。

再帰的回避策

これらのハードルを克服するには、賢い回避策は、マクロ評価再帰として知られる手法を活用します。重要なアイデアは、実際にマクロ自体を呼び出すことなく、マクロ呼び出しをシミュレートするマクロ テキストを出力することです。

次のマクロを考えてみましょう:

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

次のマクロがあるとします:

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

マクロ A(まあ) を評価すると、次の出力が生成されますtext:

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

このテキストはマクロ置換プレースホルダーとして機能します。これをプリプロセッサに戻してさらに拡張し、マクロ評価プロセスを続行できます。

この再帰を容易にするために、一連の 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__)))
ログイン後にコピー

各マクロは適用されます。複数レベルの評価が行われるため、適用されているマクロの効果が増幅されます。

再帰

再帰を制御するために、特別なマクロ MAP_END が定義されています。

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

このマクロを評価しても何も行われず、実質的に再帰は終了します。

次の課題は、再帰を続行する代わりに MAP_END をいつ使用するかを決定することです。これを実現するために、MAP_NEXT マクロはリスト項目を特別なリスト終了マーカーと比較します。一致する場合は MAP_END が返されます。それ以外の場合は、次のパラメータを返します:

#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 マクロを作成できます。各項目:

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

このマクロは、ANSI 準拠を保証するための追加の引数とともに、リストの最後にリストの終わりマーカーを配置することで機能します。次に、リストを複数の EVAL マクロ呼び出しに渡し、結果を返します。

この手法は、マクロ引数でマクロを使用する際の問題に対する創造的な解決策を提供します。これにより、高度なマクロ操作機能が有効になり、プログラマは新しい方法でプリプロセッサの機能を拡張できます。

以上がC で再帰マクロを実装するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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