宏评估订单

时间:2012-01-06 07:14:01

标签: c++ c macros c-preprocessor

  

可能重复:
  # and ## in macros

为什么第二个printf的输出是f(1,2)评估宏的顺序是什么?

#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)

int main()
{
  printf("%s\n",h(f(1,2)));
  printf("%s\n",g(f(1,2)));
  return 0;
}

output 12 
       f(1,2)

3 个答案:

答案 0 :(得分:18)

来自http://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html#Argument-Prescan

  

宏参数在被替换为宏体之前完全是宏扩展的,除非它们被字符串化或粘贴到其他标记。替换后,将再次扫描整个宏体(包括替换参数),以便扩展宏。结果是参数被扫描两次以扩展其中的宏调用。

含义:

  • f连接其参数,因此其参数未展开
  • h不会对其参数进行字符串化或连接,因此它的参数会被扩展。
  • g将其参数字符串化,因此其参数未展开

h(f(1,2)) -> g(12) -> "12"

g(f(1,2)) -> "f(1,2)"

答案 1 :(得分:7)

参数在替换到替换列表之前进行宏替换,除了,它作为#(stringize)或##(连接)的操作数出现

在宏h中,参数a不是这两个运算符之一的参数,因此参数被宏替换,然后替换为替换列表。也就是说,参数f(1,2)被宏替换为1##2,然后转换为12,然后将其替换为g(12),这将(再次)进行宏替换成为"12"

当您直接调用g时,参数a #运算符的参数,因此其参数在替换之前不会被宏替换: f(1,2)直接替换为替换列表,产生"f(1,2)"

答案 2 :(得分:3)

我不确定评估顺序对于C或C ++宏来说是一个有意义的术语,因为宏扩展在编译时发生

至于为什么第二个输出是f(1,2)是因为宏是文本替换。展开g(f(1,2))后,g的参数就是令牌f(1,2)的序列,并且会被字符串化。

考虑C编译器。在第二个printf的上下文中,它读取g令牌,认识到它是lexing&amp;的一个宏。解析时间然后扩展该宏调用。编译器基本上是这样做的:如果当前令牌是一个宏名称,那么在lexing你的代码时展开它。宏扩展只在可能的情况下发生(因此对于带参数的宏需要左括号),并尽快完成。