简体   繁体   English

# 和 ## 在宏中

[英]# and ## in macros

  #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.仅通过查看程序,人们“可能”期望输出对于两个 printf 语句都是相同的。 But on running the program you get it as:但是在运行程序时,你会得到它:

bash$ ./a.out
12
f(1,2)
bash$

Why is it so?为什么会这样?

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 is the operand of # , the argument is not expanded but instead immediately stringified ( "f(1,2)" ).因为g的参数#的操作数,所以参数没有扩展而是立即字符串化( "f(1,2)" )。 Because h 's parameter is not the operand of # nor ## , the argument is first expanded ( 12 ), then substituted ( g(12) ), then rescanning and further expansion occurs ( "12" ).因为h的参数既不#也不是##的操作数,参数首先被扩展( 12 ),然后被替换( g(12) ),然后重新扫描并进一步扩展( "12" )。

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 )。

Below are some related concepts to your question:以下是与您的问题相关的一些概念:

Argument Prescan : 参数预扫描

Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they are stringified or pasted with other tokens.宏参数被替换为宏体之前是完全宏扩展的,除非它们被字符串化或与其他标记粘贴 After substitution, the entire macro body, including the substituted arguments, is scanned again for macros to be expanded.替换后,整个宏体,包括被替换的参数,将再次扫描以查找要扩展的宏。 The result is that the arguments are scanned twice to expand macro calls in them.结果是参数被扫描两次以扩展其中的宏调用。

Stringification字符串化

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 pasting or 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 as Stringification

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.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM