C预处理程序,递归宏 [英] C preprocessor, recursive macros

查看:95
本文介绍了C预处理程序,递归宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么M(0)和N(0)有不同的结果?

Why does M(0) and N(0) have different results?

#define CAT_I(a, b) a ## b
#define CAT(a, b) CAT_I(a, b)

#define M_0 CAT(x, y)
#define M_1 whatever_else
#define M(a) CAT(M_, a)
M(0);       //  expands to CAT(x, y)

#define N_0() CAT(x, y)
#define N_1() whatever_else
#define N(a) CAT(N_, a)()
N(0);       //  expands to xy

推荐答案

实际上,这取决于您对语言标准的解释.例如,在mcpp(一种严格符合语言标准文本的预处理器实现)下,第二个也会产生CAT(x, y); [结果中删除了多余的换行符]:

In fact, it depends on your interpretation of the language standard. For example, under mcpp, a preprocessor implementation that strictly conforms to the text of the language standard, the second yields CAT(x, y); as well [extra newlines have been removed from the result]:

C:\dev>mcpp -W0 stubby.cpp
#line 1 "C:/dev/stubby.cpp"
        CAT(x, y) ;
        CAT(x, y) ;
C:\dev>

其中存在已知的不一致 C ++语言规范(尽管我不知道C的缺陷列表在哪里,但C规范中存在相同的不一致之处).规范指出,最后的CAT(x, y)不应被宏替换.目的可能是应该对其进行宏替换.

There is a known inconsistency in the C++ language specification (the same inconsistency is present in the C specification, though I don't know where the defect list is for C). The specification states that the final CAT(x, y) should not be macro-replaced. The intent may have been that it should be macro-replaced.

引用链接的缺陷报告:

早在1980年代,WG14的一些人就了解到,不可替换"字词与产生伪代码的尝试之间存在微小差异.

Back in the 1980's it was understood by several WG14 people that there were tiny differences between the "non-replacement" verbiage and the attempts to produce pseudo-code.

委员会的决定是,没有任何野外"可行的程序会涉足这一领域,而减少不确定性并不值得改变实施或程序的一致性状态.

The committee's decision was that no realistic programs "in the wild" would venture into this area, and trying to reduce the uncertainties is not worth the risk of changing conformance status of implementations or programs.


那么,为什么对于大多数常见的预处理器实现,M(0)的行为与N(0)的行为不同?在替换M时,CAT的第二次调用完全由第一次调用CAT产生的令牌组成:


So, why do we get different behavior for M(0) than for N(0) with most common preprocessor implementations? In the replacement of M, the second invocation of CAT consists entirely of tokens resulting from the first invocation of CAT:

M(0) 
CAT(M_, 0)
CAT_I(M_, 0)
M_0
CAT(x, y)

如果将M_0定义为由CAT(M, 0)替换,则替换将无限递归.预处理器规范通过停止宏替换来明确禁止这种严格递归"替换,因此CAT(x, y)不能被宏替换.

If M_0 was instead defined to be replaced by CAT(M, 0), replacement would recurse infinitely. The preprocessor specification explicitly prohibits this "strictly recursive" replacement by stopping macro replacement, so CAT(x, y) is not macro replaced.

但是,在替换N时,CAT的第二次调用仅包含部分由第一次调用CAT产生的令牌:

However, in the replacement of N, the second invocation of CAT consists only partially of tokens resulting from the first invocation of CAT:

N(0)
CAT(N_, 0)       ()
CAT_I(N_, 0)     ()
N_0              ()
CAT(x, y)
CAT_I(x, y)
xy

此处,CAT的第二次调用部分由CAT的第一次调用产生的令牌形成,部分由其他令牌(即N的替换列表中的())形成.替换不是严格的递归,因此,当替换CAT的第二次调用时,它不能产生无限的递归.

Here the second invocation of CAT is formed partially from tokens resulting from the first invocation of CAT and partially from other tokens, namely the () from the replacement list of N. The replacement is not strictly recursive and thus when the second invocation of CAT is replaced, it cannot yield infinite recursion.

这篇关于C预处理程序,递归宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆