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
行为。不同的是什么时候被解雇,这是一个更好的说法。解释替换发生的时间对你的回答很有帮助。