C ++宏间接

时间:2014-07-11 23:22:12

标签: c++

有人可以解释为什么会有效:

#include <iostream>

using namespace std;

#define cat(a,b) cat_1(a,b) 
#define cat_1(a,b) a ## b
int main()
{
    cat(c,cat(o,cat(u,t))) << "Hello world!";
    return 0;
}

但是具有一个较少级别的宏间接的相同代码不会:

#include <iostream>

using namespace std;

#define cat(a,b) a ## b
int main()
{
    cat(c,cat(o,cat(u,t))) << "Hello world!";
    return 0;
}

我看过这个:

http://www.boost.org/doc/libs/1_55_0/libs/preprocessor/doc/

虽然它说明了问题但我仍然不明白这是如何解决它的。当我在这个(g ++ -E)上运行预处理器时:

#include <iostream>

using namespace std;

#define cat(a,b) cat_1(a,b) 

int main()
{
    cat(c,cat(o,cat(u,t))) << "Hello world!";
    return 0;
}

它将该行扩展为:

cat_1(c,cat_1(o,cat_1(u,t))) << "Hello world!"

所以看起来问题应该仍然存在,因为它直接映射到只有'cat'的行

2 个答案:

答案 0 :(得分:4)

在重新扫描宏替换以进行更多宏调用之前,应用

##运算符。外部调用首先扩展为ccat(o,cat(u,t)),然后扩展到ccat(o, ut)并停在那里。

额外间接允许在令牌粘贴之前重新扫描。

答案 1 :(得分:0)

简短回答:宏定义中存在##运算符会停止正常级联替换它附近的宏参数。

获取第一个(工作)版本的子集:

#define cat(a,b) cat_1(a,b) 
#define cat_1(a,b) a ## b
cat(o,cat(u,t))

最后一行是标记化的:

cat ( o , cat ( u , t ) )

cat和(标记表示调用cat()宏的开始,因此预处理器开始用cat()的定义替换它:

cat_1(

此时它必须替换&#34; a&#34;传入的参数(即&#34; o&#34;),所以它继续:

cat_1(o,

现在必须更换参数&#34; b&#34;传入的参数(即&#34; cat(u,t))&#34;),但这个参数本身就是一个宏调用,因此在替换为&#34; cat_1(u,t)之前会被扩展)&#34;然后到&#34;你## t&#34;最后到了&#34; ut&#34;,所以,回到顶层,我们最终得到:

cat_1(o,ut)

这是重新扫描,变成:

o ## ut

最后到

正如所料。

在非工作的情况下,##附近的非扩展规则发挥作用:

#define cat(a,b) a ## b
cat(o,cat(u,t))

这次预处理器开始替换外部cat()调用时,会立即遇到参数&#34; a&#34;并且必须用传递的参数&#34; o&#34;替换它,这很好,后跟##:

o ##

现在进入&#34; b&#34;它必须用参数替换&#34; cat(u,t)&#34;。 然而,与上面的工作示例不同,这次,参数不会递归扩展,因为根据C标准,紧接在##运算符之前或之后的参数不得递归展开。所以,它只是离开了猫(你,t)&#34;因为它得到它并最终得到:

o ## cat(u,t)

然后折叠成

ocat(u,t)

这是预处理器停止的地方,因为它不知道&#34; ocat&#34;。

停止递归参数扩展的##(和#)预处理器操作符在C标准的6.10.3.1节中列出。