'#'在C中究竟做了什么?

时间:2013-10-05 13:39:51

标签: c c-preprocessor

我有一个程序。

#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;
}

此程序正常工作并输出为:

12
f(1, 2)

我不明白编译器如何提供此输出。

a##b#a中的#功能是什么?

3 个答案:

答案 0 :(得分:12)

##将两个令牌连接在一起。

重要的是它只能在预处理器中使用。

#运算符用于字符串化标记。

例如: -

#(a ## b)变为#ab <{1}}成为"ab"

所以h(f(1,2))变为“f(1,2)”

另请注意,###是两个不同的运算符。

  

预处理程序运算符 ## 提供了一种连接实际的方法   宏观扩张期间的争论。如果一个参数在替换   文本与##相邻,参数由实际替换   参数,##和周围的空白区域被删除了   结果被重新扫描。

另请查看 Concatenation 了解详情。

来自here: -

  

<强>字串化

     

有时您可能希望将宏参数转换为字符串   不变。参数不会在字符串常量内替换,但是你   可以使用'#'预处理运算符。当一个宏参数   与前导“#”一起使用,预处理器将其替换为   实际参数的文字文本,转换为字符串常量。   与普通参数替换不同,参数不是   首先是宏观扩张。这称为字符串化。

     

无法将参数与周围文本组合在一起   将它们串联起来。相反,你可以写一系列相邻的   字符串常量和字符串化参数。预处理器会   用字符串常量替换字符串化的参数。 C   然后编译器将所有相邻的字符串常量合并为一个   长串。

答案 1 :(得分:4)

##被称为“令牌粘贴”运算符,或“合并”运算符,可用于组合两个令牌以形成实际参数。

#称为字符串化运算符,它“将宏参数转换为字符串文字而不扩展参数定义”。

这些通常称为预处理器操作符。还有一些像这样的预处理器运算符。查看C(http://msdn.microsoft.com/en-us/library/wy090hkc.aspx)中的预处理器操作符以获取更多说明。


同时结帐http://msdn.microsoft.com/en-us/library/3sxhs2ty.aspx以及该页面的“另请参阅”部分,了解有关C预处理器的更多信息。

答案 2 :(得分:4)

让我为你分解:

#define f(a,b) a##b //2 this macro is evaluated first with a = 1 and b = 2 it concatenates them and returns 12
#define g(a)   #a //4 g turns 12 into "12" (string)
#define h(a) g(a) //3 back to h which now has a = 12 and call g()

int main()
{
      printf("%s\n",h(f(1,2)));//1 printf calls the macro h() and gives it the macro f() as an argument 
      printf("%s\n",g(f(1,2)));// g here turns f(1,2) into "f(1,2)" (string)
      return 0;
}