C++ 宏观评价顺序

C++ 宏观评价顺序,c++,c,macros,c-preprocessor,C++,C,Macros,C Preprocessor,可能重复: 为什么第二个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) #包括 #定义f(a,b)a##b #定义

可能重复:

为什么第二个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)
#包括
#定义f(a,b)a##b
#定义g(a)#a
#定义h(a)g(a)
int main()
{
printf(“%s\n”,h(f(1,2));
printf(“%s\n”,g(f(1,2));
返回0;
}
产出12
f(1,2)
<>代码> > P>我不确定评价顺序是C或C++宏的有意义的术语,因为<强>宏扩展发生在编译时< /强> 

至于为什么第二个输出是
f(1,2)
是因为宏是文本替换。当展开
g(f(1,2))
时,
g
的参数是
f(1,2)
标记的序列,这些标记被字符串化


从C编译器的角度考虑。在第二个
printf
的上下文中,它读取一个
g
标记,在词法分析和解析时识别它是一个宏,然后展开该宏调用。编译器基本上是这样做的:如果当前标记是宏名称,那么在分析代码时将其展开。宏扩展只在可能的情况下发生(因此对于带有参数的宏,需要左括号),并尽快完成。

在将参数替换到替换列表中之前,会对参数进行宏替换,除非它显示为
(stringize)或
#
(串联)的操作数

在宏
h
中,参数
a
不是这两个运算符之一的参数,因此该参数将被宏替换,然后替换到替换列表中。也就是说,参数
f(1,2)
被宏替换为
1##2
,然后被替换为
12
,然后被替换为
g(12)
,这也是宏替换为
“12”

当您直接调用
g
时,参数
a
#
操作符的参数,因此在替换之前,它的参数不会被宏替换:
f(1,2)
直接替换到替换列表中,从中生成
“f(1,2)”

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

意思是:

  • f连接其参数,因此其参数不展开
  • h不字符串化或连接它的参数,因此它的参数被扩展
  • g将其参数字符串化,因此其参数不会展开
h(f(1,2))->g(12)->“12”


g(f(1,2))->“f(1,2)”

这在技术上是不正确的。只有在宏中字符串化或连接的情况下,参数才会是文本替换。我不确定您是否理解
cpp
只是一个文本重写系统。如果宏严格使用文本替换,那么
h(f(1,2))
应该扩展到
“f(1,2)”
,但这也是文本替换,这是标准的
cpp
行为。不同的是什么时候被解雇,这是一个更好的说法。解释替换发生的时间对你的回答很有帮助。