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

查看:24
本文介绍了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 的第二次调用仅包含 部分 由第一次调用 产生的标记>猫:

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 的替换列表中的 code>.替换不是严格递归的,因此当 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天全站免登陆