【问题标题】:Unable to call one #define macro from another [duplicate]无法从另一个调用一个#define 宏[重复]
【发布时间】:2015-04-14 19:59:46
【问题描述】:

我有这些台词

#define LOG(fp, fmt, ...) fprintf(fp, "%s:%d: "fmt, __FILE__, __LINE__, ## __VA_ARGS__) 
#define OUT(fmt, ...) LOG(stdout, fmt, __VA_ARGS__) 

编译器显示 OUT 是错误的。如何从 OUT 中调用 LOG?

错误信息:

  1. LOG 中“)”标记之前的预期表达式
  2. 当我将它用作OUT("Hello world");时出现扩展错误

【问题讨论】:

  • 您使用的是什么编译器,对于OUT 的用途,它给出了什么错误消息?
  • 错误信息 1) LOG 中的“)”标记之前的预期表达式和 2) 当我将其用作 OUT("Hello world"); 时出现扩展错误;
  • @alk 我刚从书中得到它,它可以工作
  • Err .. “它有效”?你的问题表明它没有。
  • @alk LOG 本身可以正常工作。只有当我从 OUT 调用它时,才会出现错误

标签: c


【解决方案1】:

简短的解释,因为我从 cmets 中得知这是代码中的货物:##__VA_ARGS__ 中的 ## 是预处理器的非标准扩展(最初来自 gcc,现在也被clang支持)。其效果是,如果在没有可变参数的情况下调用可变参数宏,则会删除前面多余的逗号。也就是说,在哪里

#define FOO(bar, ...) foo(bar, __VA_ARGS__)

不能用一个参数调用,因为它会扩展为foo(argument,)

#define FOO(bar, ...) foo(bar, ##__VA_ARGS__)

可以,因为逗号被静默删除,扩展为foo(argument)

因此,您的问题的解决方案是使用

//                                     vv--- these are important here
#define OUT(fmt, ...) LOG(stdout, fmt, ##__VA_ARGS__) 

否则在只有一个参数的OUT 的扩展中,LOG 中的__VA_ARGS__ 不会为空,因为它是从扩展而来的

LOG(stdout, "Hello, world.",)

而不是

LOG(stdout, "Hello, world.")

...然后LOG__VA_ARGS__ 之前的## 将无效。您会收到编译器消息,因为 LOG 的扩展中有一个额外的逗号(fprintf 调用以 ,) 结尾)。

Link to specifics.

【讨论】:

  • 酷,如此简单!我刚刚测试过了!
  • 就我看到 gcc 的警告而言,这种方法不符合 C99。使用-pedantic 我得到warning: ISO C99 requires rest arguments to be used [enabled by default]
  • @alk 是正确的。它最初是由 gcc 实现的,我刚刚尝试了 clang 3.5,它也支持它,但如果 MSVC 没有窒息它,我会感到惊讶。但是,MSVC 会在不带 ## 的情况下抑制尾随逗号,因此虽然彻底消除了混淆,但可以使用最常见的编译器解决问题。
【解决方案2】:

OUT(fmt, ..) 中的 ... 意味着需要传递至少一个参数,然后是 fmt。比如:

OUT("%s", "Hello World");

如果这样做,## 将无用,宏应如下所示:

#define LOG(fp, fmt, ...) fprintf((fp), "%s:%d: "fmt, __FILE__, __LINE__, __VA_ARGS__) 
#define OUT(fmt, ...) LOG(stdout, fmt, __VA_ARGS__) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 2020-12-31
    • 2020-06-22
    • 1970-01-01
    • 2015-02-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多