【问题标题】:preprocessor macro stringify预处理器宏字符串化
【发布时间】:2019-06-21 10:05:38
【问题描述】:

我试图理解预处理器。

为什么下面的预处理器宏中的一个不起作用,而另一个却起作用

#pragma 和 _Pragma 有什么区别

为什么我们要用 ASTRINGZ 包裹 STRINGZ?

#define STRINGZ(x)                                #x
#define ASTRINGZ(x)                               STRINGZ(x)

#define DO_PRAGMA(x) _Pragma (#x)
#define TODO(x) DO_PRAGMA(message ("TODO - " #x))
#define msg(s) TODO( s " - @ - " ASTRINGZ(__FILE__))

msg ("This doesnt work")
#pragma message "but this does: " ASTRINGZ(__FILE__) 

来源:

https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html

http://forums.codeguru.com/showthread.php?215151-LINE-MACRO-to-string-literal&p=613574#post613574

【问题讨论】:

  • 我猜#pragma 来自VC
  • @Mayur #pragma 是非标准 C 的标准 C :) #pragma 之后的内容将是特定于编译器的,需要不识别它的编译器忽略它。无论如何,这不是问题所在,而是宏参数的预处理器扩展。
  • @StoryTeller 更好的欺骗? stackoverflow.com/questions/16989730/…
  • @StoryTeller 好吧,也许这个问题已经足够具体了。我会重新打开。并且还交换了 wiki 中的规范欺骗,因为我同意我使用的第一个没有很好的答案。
  • @Hasan alattar 关于#pragma 和_Pragma 的区别,前者是预处理器指令,后者是在其他预处理器指令中使用的运算符。两者都是标准 C 并用于可移植地指示以下内容不是标准 C。

标签: c compilation c-preprocessor pragma


【解决方案1】:

为什么下面的预处理器宏中的一个不起作用,而另一个却起作用

虽然预处理器会扩展当前扩展产生的大多数其他宏,但它只会执行一个扩展步骤。所以ASTRINGZ(__FILE__)在传递给TODO的字符串化之前不会一直扩展。

您有多种选择来处理这个问题,最简单的方法是依赖 __FILE__ 已经是一个字符串字面量这一事实。

#define msg(s) TODO( s " - @ - " __FILE__)

但是,如果您想尝试宏扩展,可以尝试延迟技术。这将延迟 TODO 本身实际扩展的时刻,并给参数自己扩展的时间。

#define EMPTY() 
#define DEFER(m) m EMPTY EMPTY()()

#define msg(s) DEFER(TODO)( s " - @ - " ASTRINGZ(__FILE__))

以上内容使( s " - @ - " ASTRINGZ(__FILE__)) 不是宏的参数,因此ASTRINGZ 将被扩展。然而DEFER(TODO) 是一个宏,因此它将被扩展为TODO EMPTY EMPTY()()。这将需要两个扩展周期(每个 EMPTY() 和 TODO (...) 都将被交回预处理器。此时所有内容都应该正确扩展。

#pragma 和 _Pragma 有什么区别

_Pragma 是另一种提供编译器特定编译指示指令的标准方式。不同的是_Pragma可以是宏扩展的结果,而#pragma是指令可能不是。

为什么我们要用 ASTRINGZ 包裹 STRINGZ?

这是另一种延迟技术。如果ASTRINGZ 的参数本身是一些重要的预处理器扩展的结果。

【讨论】:

  • @user694733 - 不是真的。 "x" 的字符串化是"\"x\"",这是标准的。 OP 只是冗余地重新包装。但这对于这个特定问题来说是无关紧要的,并且 OP 在继续改进实用程序时要弄清楚。
  • 我无法使您展示的示例正常工作。尽管我从您的回答中了解到我是随机包装的。我从 TODO 宏中删除了“#”,一切正常!
  • @Hasanalattar - 我不知道你做了什么以及它是如何不起作用的,显然我不是通灵者。但是,如果您仍然无法扩展整个内容,则解决方案可能是将EMPTY EMPTY()() 变成EMPTY EMPTY EMPTY EMPTY()()()()
  • @user694733 - _Pragma 的参数必须是一个字面量,其内容为#pragma。所以如果我们想要#pragma message ... 的等价物,我们需要产生_Pragma("message ...")。因此,鉴于TODO,DO_PRAGMA 中的#x 是正确的。
  • @StoryTeller 我没有改变任何东西。一旦它不起作用,我从原始问题中粘贴了我的代码.. 可能是因为您假设我使用的是 Microsoft VC,而我使用的是具有编译器的 Atmel Studio:arm-none-eabi-g++.exe .. image 无论如何谢谢你答案是有道理的,但我无法理解 DEFER 和 EMPTY 部分或使其工作..
猜你喜欢
  • 2012-07-21
  • 2017-09-18
  • 2011-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-29
  • 2011-09-24
相关资源
最近更新 更多