延迟宏扩张

imr*_*mre 1 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
Run Code Online (Sandbox Code Playgroud)

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

Pau*_* II 8

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

M(a) ## X //Compiler error can't paste ')' and X
Run Code Online (Sandbox Code Playgroud)

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

#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)
Run Code Online (Sandbox Code Playgroud)

但是,在您的情况下,这仍然不起作用:

 CAT(M(a), X) //expands to 0
Run Code Online (Sandbox Code Playgroud)

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

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

CAT(M(arg), X)() // expands to 1
M(arg)()     //  expands to 0
Run Code Online (Sandbox Code Playgroud)

函数宏更强大,您可以延迟它们的扩展.以下是如何在一次扫描中延迟它们的方法:

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

N_() //Expands to 0
DEFER(N_)() //Expands N_ ()
Run Code Online (Sandbox Code Playgroud)

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