代码之家  ›  专栏  ›  技术社区  ›  Parduz

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

  •  3
  • Parduz  · 技术社区  · 7 年前

    我有两个宏:

     #define LogFunction(str)       fprintf(stdout, "%s: %s\n",__FUNCTION__,(str))
     #define LogPrintf(f_, ...)     fprintf(stdout, (f_), ##__VA_ARGS__)
    

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

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

    我想改变的是

    1. 添加 功能 在logprintf的开头,因为它在logfunction中
    2. 在logprintf的末尾添加“\n”,而不必记住将其放入自己的日志中。

    所以最后我可以只为输出一个宏。

    我试着理解如果 Appending to __VA_ARGS__ 本可以是有用的,但我承认,我不明白它是否与我的案件有关:(

    谢谢。

    2 回复  |  直到 7 年前
        1
  •  2
  •   John Bollinger    7 年前

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

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

    但是,请注意,在标准C中, LogPrimtf 宏至少需要 参数,以及 ## 没有地方。我把它放在这里只是因为你在原始代码中使用它。

    但是,如果必须接受字符串文本以外的格式字符串表达式,那么最简单的选择是执行多个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;
    }
    
        2
  •  5
  •   Jean-François Fabre    7 年前

    为什么不分三步做呢?

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

    它可以打印3张照片,但至少很简单,可以满足你的需要。这个 do while(0) 技巧确保这是一个唯一的块(使用时 if 不带大括号),需要分号。