延迟宏扩张

时间:2011-07-12 21:24:52

标签: c-preprocessor

考虑以下代码:

#define N_ 0
#define N_X 1
#define M(a) N_

M(arg)X;    //  #1 -- I'd like this to expand to N_X, and ultimately 1; but it's 0X instead
M(arg);     //  #2 -- this should and does expand to 0

#1的问题是,在扩展M()之后,结果包含N_,连接之前,预处理器找到并展开它。 我可以以某种方式延迟重新扫描结果以进一步扫描宏,以便预处理器找到N_X而不是N_?

2 个答案:

答案 0 :(得分:8)

首先,N_ XN_X之间存在差异。第一个是两个令牌。要形成一个令牌,您必须使用令牌粘贴运算符##,但此运算符禁止宏扩展,因此:

M(a) ## X //Compiler error can't paste ')' and X

导致编译错误,因为它尝试粘贴M(a)而不是N_。您可以通过使用额外级别的宏(这是非常常用的宏)允许宏在粘贴之前展开:

#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)

但是,在您的情况下,这仍然无效:

 CAT(M(a), X) //expands to 0

这是因为,您使用的是对象宏,而不是函数宏。如果将其更改为功能宏,它将按您的需要工作:

#define N_() 0
#define N_X() 1
#define M(a) N_

CAT(M(arg), X)() // expands to 1
M(arg)()     //  expands to 0

功能宏功能更强大,您可以延迟它们的扩展。以下是如何将它们延迟一次扫描:

#define EMPTY()
#define DEFER(x) x EMPTY()

N_() //Expands to 0
DEFER(N_)() //Expands N_ ()

像这样延迟宏扩展是在预处理器中实现递归的方法之一。

答案 1 :(得分:1)

没有。预处理器逐行工作,不执行任何递归或回溯。它读取一行,处理特殊的#行或替换某些行,然后转到下一行。这也意味着它不会在#define之前或#undef之后进行任何替换。你必须解决这个问题。