考虑以下代码:
#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_?
首先,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)
像这样延迟宏扩展是在预处理器中实现递归的方法之一.