我们如何解释这个复杂的C++预处理器宏替换

Jav*_*Man 5 c++ macros c-preprocessor

我正在研究关于C++预处理器如何处理宏替换的C++标准(我需要自己实现C++预处理器的一个子集).这是我为学习创建的一个例子:

  #define a x
  #define x(x,y) x(x+a, y+1)

  a(x(90, 80), a(1,2))
Run Code Online (Sandbox Code Playgroud)

通过要求VC++ 2010生成预处理器输出文件,我发现上面的内容a(x(90, 80), a(1,2))变为:

90(90+x, 80+1)(90(90+x, 80+1)+x, 1(1+x, 2+1)+1);
Run Code Online (Sandbox Code Playgroud)

但是预处理器如何提出这个输出呢?规则太复杂,无法理解.有人可以解释预处理器为提出这样的结果所做的所有步骤吗?

Syn*_*xis 6

旧答案,订单不准确(见编辑):

让我们从你的表达开始:

a(x(90, 80), a(1, 2))
Run Code Online (Sandbox Code Playgroud)

现在,既然我们已经#define a x扩展到:

  x(x(90, 80), x(1, 2))
//  ^^^^^^^^^  ^^^^^^^
//   arg 'x'    arg 'y'
Run Code Online (Sandbox Code Playgroud)

我们可以应用定义x(x,y),即#define x(x,y) x(x+a, y+1):

x(90, 80)(x(90, 80)+a, x(1, 2)+1)
Run Code Online (Sandbox Code Playgroud)

还有另一个将会扩展的通行证x(...).您还可以注意到,+a上一个表达式中的那个>已扩展为+x:

  90(90+a, 80+1)(90(90+a, 80+1)+x, 1(1+a, 2+1)+1)
//                             ^^
//                          expanded
Run Code Online (Sandbox Code Playgroud)

最后:+a遗骸扩大到+x:

  90(90+x, 80+1)(90(90+x, 80+1)+x, 1(1+x, 2+1)+1)
//     ^^             ^^              ^^
//  expanded       expanded        expanded
Run Code Online (Sandbox Code Playgroud)

我希望没有错误.

请注意,您的定义x(x,y)非常模糊(对于人类):宏名称和参数共享相同的名称.请注意,即使没有,宏也不是递归的,所以如果你有

#define x(u,v) x(u+a, b+1)
Run Code Online (Sandbox Code Playgroud)

不会扩展到类似的东西

x(u+a+a+a+a, b+1+1+1+1)
Run Code Online (Sandbox Code Playgroud)

这是因为在x定义宏时,其名称对内部宏定义"不可用".

另一个小注意事项:对于gcc,输出不完全相同,因为gcc在替换的标记之间添加空格(但如果删除它们将与msvc相同).

编辑:从dyp的评论,这个顺序不是确切的.实际上,首先扩展参数然后在宏表达式中替换.句子的最后一部分很重要:这意味着不重新评估宏参数列表.可以把它想象成:使用占位符代替参数扩展宏,然后扩展参数,然后用各自的参数替换占位符.所以,简而言之,这相当于我之前解释过的,但这里是正确的顺序(详细操作):

> Expansion of a(x(90, 80), a(1, 2))
    > Substitution of 'a' into 'x' (now: 'x(x(90, 80), a(1, 2))')
    > Expansion of x(x(90, 80), a(1, 2)) [re-scan]
        > Macro 'x(X, Y)' is expanded to 'X(X+a,Y+1)'
        > Expansion of 'x(90,80)' (first argument)
            > Macro 'x(X,Y)' is expanded to 'X(X+a,Y+1)'
            > Argument '90' does not need expansion (ie, expanded to same)
            > Argument '80' does not need expansion (ie, expanded to same)
            > Substitution with 'X=90' and 'Y=80': '90(90+a, 80+1)'
            > Re-scan of result (ignoring macro name 'x')
                > Substitution of 'a' into 'x': '90(90+x, 80+1)'
        > Expansion of 'a(1,2)' (second argument)
            > Substitution of 'a' into 'x'
            > Expansion of 'x(1,2)' [re-scan]
                > Macro 'x(X,Y)' is expanded to 'X(X+a,Y+1)'
                > Argument '1' does not need expansion (ie, expanded to same)
                > Argument '2' does not need expansion (ie, expanded to same)
                > Substitution with 'X=1' and 'Y=2': '1(1+a, 2+1)'
                > Re-scan of result (ignoring macro name 'x')
                    > Substitution of 'a' into 'x': '1(1+x, 2+1)'
        > Substitution with X='90(90+x, 80+1)' and Y='1(1+x, 2+1)'
          Result: '90(90+x, 80+1)(90(90+x, 80+1)+a, 1(1+x, 2+1)+1)'
        > Re-scan of result
            > Substitution of 'a' into 'x'
              Result: '90(90+x, 80+1)(90(90+x, 80+1)+x, 1(1+x, 2+1)+1)'
Last result is result of whole expansion:
    90(90+x, 80+1)(90(90+x, 80+1)+x, 1(1+x, 2+1)+1)
Run Code Online (Sandbox Code Playgroud)