良好的详细程度宏(C99)

时间:2012-02-24 22:53:49

标签: c macros verbosity

我正在寻找我想象的是一个相当常见的宏。我想通过定义以下形式的一堆宏来模拟许多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 个答案:

答案 0 :(得分:5)

GNU C预处理器有一个special feature,当没有参数填充可变参数部分时,可以通过将令牌粘贴操作符##添加到__VA_ARGS__来删除尾随逗号:< / p>

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

或者,如果您希望完全符合C99,则可以将格式字符串参数合并到省略号中,但在这种情况下,您还需要重构代码,因为您要包含额外的{{1}格式字符串和varargs之间的参数。这样的事情可能有用:

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"),而不使用任何非C99编译器扩展。

修改

另请注意,我在宏中反转了myprintf(prog, "Output")条件,因为如果在没有大括号的if语句中调用宏,可能会出现一些奇怪的问题 - 请参阅this FAQ详细解释。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

你应该写一个小的支持功能,这样你就可以干净利落地完成工作:

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

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

我假设optvprog都是全局变量。这些会进入标题(你不会在程序中自己写出来,不是吗?)。

该功能可以是:

#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);
}

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

答案 3 :(得分:0)

试试这个:

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

我认为这可以解决您描述的问题,最后else解决了另一个问题。