C语言 # 和 ## 在宏中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4364971/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
# and ## in macros
提问by algo-geeks
#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;
}
Just by looking at the program one "might" expect the output to be, the same for both the printf statements. But on running the program you get it as:
仅仅通过查看程序,人们“可能”期望输出对于两个 printf 语句都是相同的。但是在运行程序时,你会得到它:
bash$ ./a.out
12
f(1,2)
bash$
Why is it so?
为什么会这样?
采纳答案by Christoffer
Because that is how the preprocessor works.
因为这就是预处理器的工作方式。
A single '#' will create a string from the given argument, regardless of what that argument contains, while the double '##' will create a new token by concatenating the arguments.
单个 '#' 将从给定参数创建一个字符串,无论该参数包含什么,而双 '##' 将通过连接参数创建一个新标记。
Try looking at the preprocessed output (for instance with gcc -E) if you want to understand better how the macros are evaluated.
gcc -E如果您想更好地了解宏的评估方式,请尝试查看预处理的输出(例如使用)。
回答by Joe Bloggs
An occurrence of a parameter in a function-like macro, unless it is the operand of #or ##, is expanded before substituting it and rescanning the whole for further expansion. Because g's parameter isthe operand of #, the argument is not expanded but instead immediately stringified ("f(1,2)"). Because h's parameter is notthe operand of #nor ##, the argument is first expanded (12), then substituted (g(12)), then rescanning and further expansion occurs ("12").
在类似函数的宏中出现的参数,除非它是#or的操作数,否则会##在替换它之前扩展,并重新扫描整个以进行进一步扩展。因为g的参数是的操作数#,所以参数没有展开而是立即字符串化 ( "f(1,2)")。因为h的参数不是#nor的操作数##,所以参数首先被扩展(12),然后被替换(g(12)),然后重新扫描并发生进一步的扩展("12")。
回答by smwikipedia
Below are some related concepts to your question:
以下是与您的问题相关的一些概念:
Macro arguments are completely macro-expanded beforethey are substituted into a macro body, unless they are stringifiedor pastedwith other tokens. After substitution, the entire macro body, including the substituted arguments, is scanned againfor macros to be expanded. The result is that the arguments are scanned twice to expand macro calls in them.
宏参数在被替换为宏体之前是完全宏扩展的,除非它们被字符串化或 与其他标记粘贴。替换后,整个宏体,包括被替换的参数,将再次扫描以查找要扩展的宏。结果是参数被扫描两次以扩展其中的宏调用。
When a macro parameter is used with a leading ‘#', the preprocessor replaces it with the literal text of the actual argument, converted to a string constant.
当宏参数与前导“#”一起使用时,预处理器将其替换为实际参数的文字文本,转换为字符串常量。
#ABC => "ABC"<---- Note the enclosing double quote, which is added by the stringification process.
#ABC => "ABC"<---- 注意封闭的双引号,它是由字符串化过程添加的。
Token Pasting / Token Concatenation:
It is often useful to merge two tokens into one while expanding macros. This is called token pastingor token concatenation. The ‘##' preprocessing operator performs token pasting. When a macro is expanded, the two tokens on either side of each ‘##' operator are combined into a single token, which then replaces the ‘##' and the two original tokens in the macro expansion.
在扩展宏时将两个标记合并为一个通常很有用。这称为标记粘贴或标记串联。'##' 预处理运算符执行标记粘贴。扩展宏时,每个“##”运算符两侧的两个标记合并为一个标记,然后替换宏扩展中的“##”和两个原始标记。
So the detailed process of your scenario is like this:
所以你的场景的详细流程是这样的:
h(f(1,2))
-> h(12) // f(1,2) pre-expanded since there's no # or ## in macro h
-> g(12) // h expanded to g
12 // g expanded
g(f(1,2))
-> "f(1,2)" //f(1,2) is literally strigified because of the `#` in macro g. f(1,2) is NOT expanded at all.

