【问题标题】:Why is the output of the following two statements different?为什么以下两个语句的输出不同?
【发布时间】:2009-11-06 12:38:30
【问题描述】:

代码:

 #define f(a,b) a##b
 #define g(a)   #a
 #define h(a) g(a)

 main()
 {
      printf("%s\n",h(f(1,2)));  //[case 1]
      printf("%s\n",g(f(1,2)));  //[case 2]
 }

输出:

12
f(1, 2)

为什么两种情况下的输出不一样?

[我理解串联 (a##b) 和字符串转换 (#a) here,但我不明白为什么两种情况下的输出不同。]

【问题讨论】:

  • 您使用的是哪个编译器平台。如果这种行为是特定于编译器的,我不会感到惊讶。
  • 我在 Windows 上使用Cygwin gcc

标签: c function


【解决方案1】:

规范的相关部分是:

6.10.3.1

"在确定了调用类函数宏的参数后, 发生参数替换。替换列表中的参数,除非前面有 由 # 或 ## 预处理标记或后跟 ## 预处理标记(见下文),是 在其中包含的所有宏都被替换后由相应的参数替换 展开。”

也就是说,当宏参数被替换时,首先对参数进行一轮宏扩展,除非参数出现#或##。

所以g(blah) 只是将blah 字符串化。 h(blah) 首先宏扩展blah,然后将其字符串化。

当您想对宏名称进行字符串化时,差异尤其重要:

printf("The value of the " g(NULL) " macro is " h(NULL));

【讨论】:

    【解决方案2】:

    这可能是评估的顺序。在第一种情况下,h 和 f 在第一遍中被评估为 g 和 12。第二遍宏评估然后将其转换为 12。在第二种情况下,g 直接将 f(1,2) 评估为字符串。

    【讨论】:

    • 是的,我明白这一点。但是为什么会发生你刚才提到的这种情况呢?
    【解决方案3】:

    当扩展函数样式的宏时,替换列表中任何前面没有# 或紧邻## 的参数实例都将在宏扩展后被相应的参数替换。 # 之后或与## 相邻的参数不会发生宏扩展。如果扩展中有任何宏,则宏扩展在替换时递归地发生,直到没有宏剩余。 (任何宏的扩展在任何嵌套级别的扩展过程中都不会扩展自身,因此您无法获得任何无限递归。)

    在您的示例中,g(f(1,2)) 变为 f(1,2)#(没有宏参数的扩展),即“f(1, 2)”,一个字符串文字。

    h(f(1,2))变成g( 12 )是因为f(1,2)进行了宏扩展,这个扩展中还有一个宏,所以再次扩展,g( 12 )变成了“12”。

    【讨论】:

      【解决方案4】:

      C 宏不是函数。这是简单的文本替换。只需将 g(a) 中的 a 替换为 "f(1, 2)" ,这就是您的答案。

      【讨论】:

      • 所以在case1h(f(1,2)) 变成g(f(1,2))。所以,结果应该是一样的!
      • 否,因为#后面的参数没有展开。
      猜你喜欢
      • 1970-01-01
      • 2019-06-20
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2021-09-09
      • 2023-01-02
      • 2015-11-27
      相关资源
      最近更新 更多