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

时间:2014-03-18 12:24:12

标签: 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))

通过要求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);

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

1 个答案:

答案 0 :(得分:6)

旧答案,顺序不准确(见编辑):

  

让我们从你的表达开始:

a(x(90, 80), a(1, 2))
     

现在,由于我们有#define a x,它会扩展为:

  x(x(90, 80), x(1, 2))
//  ^^^^^^^^^  ^^^^^^^
//   arg 'x'    arg 'y'
     

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

x(90, 80)(x(90, 80)+a, x(1, 2)+1)
     

还有另一个会传播x(...)。你还可以注意到+a那个>之前的表达式已扩展为+x

  90(90+a, 80+1)(90(90+a, 80+1)+x, 1(1+a, 2+1)+1)
//                             ^^
//                          expanded
     

上次:剩余的+a已扩展为+x

  90(90+x, 80+1)(90(90+x, 80+1)+x, 1(1+x, 2+1)+1)
//     ^^             ^^              ^^
//  expanded       expanded        expanded
     

我希望没有错误。

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

#define x(u,v) x(u+a, b+1)

不会扩展为类似

的东西
x(u+a+a+a+a, b+1+1+1+1)

这是因为当定义宏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)