【问题标题】:Utility of macros for enum枚举宏的实用程序
【发布时间】:2014-02-18 13:28:39
【问题描述】:

我的 Linux 系统上的一个标头 socket.h 如下所示。

/* Bits in the FLAGS argument to `send', `recv', et al.  */
enum
  {
    MSG_OOB             = 0x01, /* Process out-of-band data.  */
#define MSG_OOB         MSG_OOB
    MSG_PEEK            = 0x02, /* Peek at incoming messages.  */
#define MSG_PEEK        MSG_PEEK
    MSG_DONTROUTE       = 0x04, /* Don't use local routing.  */
#define MSG_DONTROUTE   MSG_DONTROUTE
...

定义enum 有点像idiom for creating type-safe-ish constants in C,语言实际上将其视为编译时常量。

我的问题是:宏MSG_OOBMSG_PEEK、……扩展至自身的定义有什么作用?

【问题讨论】:

  • 我从未见过它,但我猜它会覆盖任何可能的替代定义,所以你确定它只是枚举。
  • MSG_OOB 扩展为MSG_OOB
  • @GIJoe 你可能在这里有所收获。它们不会扩展到预处理器可以使用的值,但如果有人需要编写它,#ifdef MSG_PEEK 将按预期工作。

标签: c c-preprocessor


【解决方案1】:

这些定义的目的是应用程序可以做类似的事情

#ifdef MSG_OOB
  some code here
#endif

宏的扩展不是递归的,因此对宏MSG_OOB 的求值会产生同名的enum 常量MSG_OOB

将常量声明为enum 也有助于例如在调试时。

【讨论】:

  • 其实这个答案是错误的。请参阅@Sneftel 的回答。
  • @GIJoe 这个答案是部分的,但它补充了 Sneftel 的好。
  • @GIJoe,为什么会?这个问题问的是目的,而不是定义的起源。
  • "这允许应用程序使用#ifdef 等来确定是否定义了宏,但宏在#if 预处理器指令中不可用,因为预处理器会将未扩展的单词macro_name 视为具有值为零。”
  • @GIJoe 引用与此答案并不矛盾。预处理器对 #if 指令中宏的解释与代码中其他地方(扩展为枚举值)之间存在差异。
【解决方案2】:

POSIX 标准要求“符号常量”(例如 MSG_DONTROUTE)是“类对象宏”,而不是枚举数。将它们定义为它们自己允许它们在枚举的上下文中使用,以及与例如#ifdef 一起正常工作。

来自 POSIX 标准:

标题应定义以下符号常量 …… MSG_DONTROUTE

还有:

符号常量...指的是 C 预处理器符号(也没有参数)。

最后,来自附录:

如果常量必须是宏,但也允许是另一种类型的常量,例如枚举常量,则在将其定义为另一种类型的常量的实现中,宏通常定义如下:

#define macro_name macro_name

这允许应用程序使用#ifdef 等来确定是否定义了宏,但宏在#if 预处理器指令中不可用,因为预处理器会将未扩展的字macro_name 视为具有零值。

【讨论】:

  • 我将接受您的回答,而不是 Jens Gustedt 的优秀回答,因为它引用了 POSIX。
  • 关键就在最后一句。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-04
  • 2012-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多