良好的详细程度宏(C99)

Huc*_*kle 0 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
Run Code Online (Sandbox Code Playgroud)

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

Ada*_*eld 5

GNU C预处理器有一个特殊功能,当没有参数填充可变参数部分时,可以通过将token-pasting操作符添加##__VA_ARGS__以下内容来删除尾随逗号:

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

或者,如果您希望完全符合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;
}
Run Code Online (Sandbox Code Playgroud)

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

编辑

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