2011-07-12 187 views
1

考虑以下代码:延迟宏扩展

#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_,和与X相连来之前,预处理器发现和其扩展。 我可以以某种方式延迟对更多宏的结果重新扫描,以便预处理器找到N_X而不是N_?

回答

7

首先在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_() 

延迟宏展开这样的是递归可在预处理器实现的途径之一。

2

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

+0

和宏一般都是邪恶的 – Drakosha

+2

Drakosha:我会不同意。了解他们和他们的陷阱,他们可以成为一个方便的工具。 – orlp

+0

nightcracker:当然,你需要学习它们,但你应该尽量避免使用它们,除非它是最后一个选项(并且我upvoted你的答案) – Drakosha