可变参数宏调用fprintf:如何向__VA_ARGS__添加参数?

时间:2018-11-28 15:13:05

标签: c macros printf variadic-macros

我有两个宏:

void MyFunction()
{
    int N=4;
    LogFunction("START");      // Outputs "MyFunction: START"
    LogPrintf("N=%d\n", N);    // Outputs "N=4"
}

所以我可以这样使用它们:

application.extensions.map.pdf=pdf
application.extensions.map.txt=txt
application.extensions.map.docx=docx

我想更改的是

    在LogPrintf的开头
  1. 添加功能,就像在LogFunction中一样
  2. 在LogPrintf的末尾添加“ \ n”,而不必记住将其放在自己的位置

所以最后我只能在输出中使用一个宏。

我试图了解Appending to __VA_ARGS__是否有用,但我承认我不了解它是否与我的案子有关:(

谢谢。

2 个答案:

答案 0 :(得分:5)

为什么不按3个步骤进行操作?

#define LogPrintf(f_, ...)   do { fprintf(stdout, "%s: ",__FUNCTION__); \
                                  fprintf(stdout, (f_), ##__VA_ARGS__); \
                                  fprintf(stdout,"\n"); } while(0)

这可以打印3张照片,但至少它很简单,可以完成您想要的操作。 do while(0)技巧可确保这是一个唯一的块(当使用不带花括号的if时),并且需要分号。

答案 1 :(得分:2)

如果您愿意依靠LogPrintf作为字符串文字的第一个参数,那么您应该能够使用字符串串联来实现您的目标:

// Assumes f_ always corresponds to a string literal:
#define LogPrintf(f_, ...)    fprintf(stdout, "%s: " f_ "\n", __FUNCTION__, ##__VA_ARGS__)

但是请注意,在标准C中,LogPrintf宏至少需要两个自变量,而##没有位置。我将其保留在这里只是因为您在原始代码中使用了它。

但是,如果您必须接受除字符串文字之外的格式字符串表达式,那么最简单的选择是执行多个I / O调用,正如另一个答案还建议的那样:

#define LogPrintf(f_, ...)    do {         \
    fprintf(stdout, "%s: ", __FUNCTION__); \
    fprintf(stdout, (f_), ##__VA_ARGS__);  \
    fputc('\n', stdout);                   \
} while (0)

请注意,在这种情况下,宏扩展为语句(无尾分号),而在另一种情况下,宏扩展为表达式。如果您想要任何I / O函数的返回值,那么在这种情况下,您将必须为此做特殊规定。

如果这也对您不起作用,那么最终的选择就是编写并使用一个辅助函数,如注释中所建议:

#define LogPrintf(f_, ...)    log_printf_impl(stdout, __FUNCTION__, (f_), ##__VA_ARGS__)

int log_printf_impl(FILE *f, const char *func, const char *fmt, ...) {
    static const char prefix[] = "%s: ";
    size_t flen = strlen(fmt);
    va_list args;
    int result = -1;
    char *aug_fmt = malloc(sizeof(prefix) + strlen(fmt) + 1);

    if (aug_fmt) {
        va_start(args, fmt);
        sprintf(aug_fmt, "%s%s\n", prefix, fmt);
        result = vfprintf(f, aug_fmt, func, args);
        va_end(args);
        free(aug_fmt);
    }

    return result;
}