0

我正在寻找写我认为是一个相当常见的宏。我想通过定义以下形式的一堆宏来模拟许多 POSIX 程序上重复的“-v”选项:

#define V1(str, ...) if(optv >= 1){printf("%s: "str,prog,__VA_ARGS__);}

int main(int argc, char* argv[])
{
  // ... stuff ...
  int i = 1;
  V1("This contains a variable: %d\n",i);
}

// Output:
// ./program: This contains a variable: 1

其中optv计算在命令行中找到的“-v”选项的数量并prog包含程序名称(均未显示)。这很好用,但问题是我必须使用一个变量。V1("Output")会产生编译错误。我总是可以使用V1("Output%s",""),但应该有一个更清洁的解决方案。

4

4 回答 4

5

GNU C 预处理器有一个特殊功能,当没有参数填充可变参数部分时,可以通过将标记粘贴运算符添加到 删除尾随##逗号__VA_ARGS__

#define V1(str, ...) if(optv < 1); else printf("%s: "str,prog, ## __VA_ARGS__)

或者,如果您希望完全符合 C99,您可以将格式字符串参数合并到省略号中,但在这种情况下,您还需要重构代码,因为您希望prog在格式字符串和可变参数。像这样的东西可能会起作用:

#define V1(...) if(optv < 1); else myprintf(prog, __VA_ARGS__)
int myprintf(const char *prog, const char *fmt, ...)
{
    // Print out the program name, then forward the rest onto printf
    printf("%s: ", prog);

    va_list ap;
    va_start(ap, fmt);
    int ret = vprintf(fmt, ap);
    va_end(ap);

    return ret;
}

然后,V1("Output")扩展为myprintf(prog, "Output")不使用任何非 C99 编译器扩展。

编辑

另请注意,我在宏中反转了条件,因为如果您在不带括号的语句中if调用宏可能会出现一些奇怪的问题- 请参阅此常见问题解答以获取详细说明。if

于 2012-02-24T23:13:07.860 回答
1

为什么不为每个详细级别使用 2 个不同的宏?一个打印消息和变量,一个只打印消息?

于 2012-02-24T22:59:07.773 回答
1

您可能应该为自己编写一个小的支持函数,以便您可以干净地完成工作:

extern void vb_print(const char *format, ...);

#define V1(...)  do { if (optv >= 1) vb_print(__VA_ARGS__); } while (0)

我假设两者optv都是prog全局变量。这些将进入标题(您不会将它们写在程序本身中,对吗?)。

该功能可以是:

#include <stdio.h>
#include <stdarg.h>

extern const char *prog;

void vb_print(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    printf("%s:", prog);
    vprintf(format, args);
    va_end(args);
}

那里没有火箭科学。您可以根据自己的喜好调整系统,允许选择信息的写入位置、刷新输出、确保末尾有换行符等。

于 2012-02-24T23:17:41.603 回答
0

尝试这个:

#define V1X(str, ...) if(optv >= 1) {printf("%s: "str,prog,__VA_ARGS__);} else
#define V1(...) V1X(__VA_ARGS__,0)

我相信解决了您描述的问题,else最后解决了另一个问题。

于 2012-02-24T23:06:40.140 回答