首页  >  文章  >  后端开发  >  尽管存在宏扩展的限制,如何在 C 中实现递归宏功能?

尽管存在宏扩展的限制,如何在 C 中实现递归宏功能?

Barbara Streisand
Barbara Streisand原创
2024-11-16 02:17:03234浏览

How can you achieve recursive macro functionality in C, despite the limitations of macro expansion?

C 中使用参数宏的递归宏

在 C 编程中,将宏递归地应用于宏参数并不简单。然而,采用复杂的解决方法,可以实现具有所需功能的 MAP 宏。

核心原则

为了启动递归,我们定义一个 MAP_OUT 宏,用作占位符宏扩展:

#define MAP_OUT

接下来,我们创建两个宏 A 和 B 来演示递归:

#define A(x) x B MAP_OUT (x)
#define B(x) x A MAP_OUT (x)

计算 A(blah) 会产生以下输出:

blah B (blah)

预处理器将 B(blah) 视为纯文本,因为它还不是宏调用。当此文本被重新处理时,它会扩展为生成:

blah blah A (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__)))

EVAL 宏通过宏调用树传播其参数,将其计算计数乘以 365。

递归终止

为了防止无限递归,我们需要一个终止机制。我们定义一个名为 MAP_END 的特殊宏:

#define MAP_END(...)

计算时,该宏不执行任何操作,有效地停止递归。

为了在递归宏和终止宏之间进行选择,我们引入 MAP_NEXT:

#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__)

MAP0 和 MAP1 将操作 f 应用于当前项 x。然后,他们检查下一项,即 peek,以确定是继续还是结束递归。

最后,我们将所有内容与顶级 MAP 宏联系在一起:

#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))

MAP 位置参数列表上的列表结束标记并将其传递给 EVAL。

通过利用这些技术,您可以在 C 中实现递归宏功能,启用复杂的基于宏的处理。

以上是尽管存在宏扩展的限制,如何在 C 中实现递归宏功能?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn