C宏扩展未按预期递归 #定义EVAL1(…)uu VA_u参数__ #我是递归的,看:_RECURSE()() #定义递归()递归 我期望: EVAL1(RECURSE()) =>EVAL1(我是递归的,看:_RECURSE()()) =>EVAL1(我是递归的,看:RECURSE()) =>我是递归的,看:RECURSE() =>我是递归的,看:我是递归的,看:_RECURSE()() 我得到的是: EVAL1(RECURSE()) =>我是递归的,看:RECURSE()

C宏扩展未按预期递归 #定义EVAL1(…)uu VA_u参数__ #我是递归的,看:_RECURSE()() #定义递归()递归 我期望: EVAL1(RECURSE()) =>EVAL1(我是递归的,看:_RECURSE()()) =>EVAL1(我是递归的,看:RECURSE()) =>我是递归的,看:RECURSE() =>我是递归的,看:我是递归的,看:_RECURSE()() 我得到的是: EVAL1(RECURSE()) =>我是递归的,看:RECURSE(),c,recursion,macros,c-preprocessor,C,Recursion,Macros,C Preprocessor,当RECURSE()作为参数传递给EVAL1时,为什么不进行第二次扩展 实现我想要的另一种方法是: #define EVAL1(...) __VA_ARGS__ #define EMPTY() #define DEFER1(m) m EMPTY() #define RECURSE() I am recursive, look: DEFER1(_RECURSE)()() #define _RECURSE() RECURSE EVAL1(RECURSE()) => I am recursiv

当RECURSE()作为参数传递给EVAL1时,为什么不进行第二次扩展

实现我想要的另一种方法是:

#define EVAL1(...) __VA_ARGS__
#define EMPTY()
#define DEFER1(m) m EMPTY()
#define RECURSE() I am recursive, look: DEFER1(_RECURSE)()()
#define _RECURSE() RECURSE

EVAL1(RECURSE())
=> I am recursive, look: I am recursive, look: _RECURSE ()()

但是我不知道为什么会这样。

C预处理器不允许递归。更准确地说,当预处理器扩展宏时,它会记住要扩展的宏。如果它发现当前正在展开的宏之一,它将保持不变

在您的示例中,评估链是:

  • EVAL1(RECURSE())
  • 展开
    EVAL1
    RECURSE()
  • 扩展
    EVAL1
    RECURSE
    我是递归的,看:_RECURSE()()
  • 扩展
    EVAL1
    \u RECURSE
    RECURSE
    我是递归的,看:RECURSE()
  • 没有什么可以扩展的了,完成了
禁止递归允许使用具有相同名称的宏包装函数。例如:

#定义foo(x,y)(printf(“DEBUG:foo在%s中第%d行被调用,uuu文件,uu行),foo(x,y))

禁止递归还保证编译将终止。(事实并非如此:您可以通过
#include
指令获得无限递归。但这比简单的递归
#define
需要更多的工作。而且终止并不一定意味着快速终止:可以构建只在很长时间后终止的预处理器扩展。)

因为在展开
RECURSE()
的点处,前处理器符号
\u RECURSE()
未知。源代码从上到下进行处理。@Lundin我认为递归和_RECURSE都是在执行EVAL1(RECURSE())时定义的。@Lundin否,OP的示例扩展在三个宏定义之后。示例是
EVAL1(RECURSE())
扩展停止的原因是预处理器检测到循环并将其中断。宏
RECURSE
已经展开,因此展开中出现的
RECURSE
的下一个实例保持不变。跳过
EVAL1
,只做
RECURSE()
,这将扩展到
我是递归的,看:RECURSE()
@Lundin OP的评论“我认为
递归
递归
都是在执行
EVAL1(RECURSE())
时定义的,措辞含糊不清,但是OP并不意味着定义的点是在扩展
EVAL1(RECURSE())
时,正如你所理解的那样,而是OP意味着它们是在扩展到达该点时定义的。#define DEFER1(m)m EMPTY()#define RECURSE()我是递归的,看:DEFER1(_RECURSE)()当递归是这样定义的时候,你如何展开呢?假设也是
#define EMPTY()
#define(定义)递归()递归
RECURSE()
→ <代码>我是递归的,看:DEFER1(_RECURSE)()()→ <代码>我是递归的,看:_RECURSE()()EMPTY()→ <代码>我是递归的,看:RECURSE()EMPTY()→ <代码>我是递归的,看:RECURSE()结果是:我是递归的,看:我是递归的,看:_RECURSE()()。我已经编辑了我的问题,您可以试一试。@cjkkk:您更新的示例扩展了两次
RECURSE
,因为宏处理会在替换类似函数的宏本身之前将参数替换为类似函数的宏,并且在替换类似函数的宏之后,它会重新扫描进一步的宏。该重新扫描将抑制刚替换的宏(类似于宏的外部函数),但不会抑制在参数中替换的宏。所以这不是递归的,只是迭代的,因为参数被宏替换(一次),然后替换的结果被宏替换(一次)。@EricPostpischil,你能给出一个答案来详细说明重新扫描如何抑制某个宏的过程吗?