首页 > 后端开发 > C++ > 正文

如何定义一个对 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) 生成文本:

blah B (blah)
登录后复制

预处理器在这里不会检测递归,因为 B (blah) 调用在此阶段只是文本。将此文本反馈回预处理器会对其进行扩展:

blah blah A (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__)))
登录后复制

每个level 放大了其前身的工作量,最终对输入进行了 365 次评估。例如,EVAL(A(blah)) 生成 365 个 blah 副本,后跟未计算的 B (blah)。此设置为特定堆栈深度限制内的递归提供了基础。

结束检测

下一个障碍是确定何时终止递归。

我们将 MAP_END 宏定义为列表结束标记:

#define MAP_END(...)
登录后复制

评估此宏不执行任何操作,表示结束递归。

要在两个宏之间进行选择,我们使用 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,然后检查下一个列表项 peek,以确定是否继续或不是。

最后,我们在顶级 MAP 宏中组装所有内容:

#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))
登录后复制

这个宏在列表末尾添加一个 () 标记,并将整个内容通过 EVAL 传递,返回结果。

为方便起见,该代码作为库在 GitHub 上提供。

以上是如何定义一个对 C 中传递给另一个宏的参数进行操作的宏?的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板