简体   繁体   English

Variadic Macro调用fprintf:如何向__VA_ARGS__添加参数?

[英]Variadic Macro calling fprintf: how to add arguments to __VA_ARGS__?

I have two macros: 我有两个宏:

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

So i can use them this way: 所以我可以这样使用它们:

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

What I would like to change is to 我想改变的是

  1. add FUNCTION at the start of the LogPrintf as it is in LogFunction 在LogPrintf的开头添加FUNCTION ,就像在LogFunction中一样
  2. add "\\n" at the end of the LogPrintf without having to remember to put it in myself 在LogPrintf的末尾添加“\\ n”,而不必记住把它放在我自己身上

so in the end i could have just one macro for my outputs. 所以最后我的输出只能有一个宏。

I've tried to understand if Appending to __VA_ARGS__ could've been useful, but i admit that i've not understood if it is related to my case :( 我试图了解附加到__VA_ARGS__是否有用,但我承认我不明白它是否与我的情况有关:(

Thanks. 谢谢。

why not doing it in 3 steps? 为什么不分3步呢?

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

this does 3 prints, but at least it's simple and does what you want. 这可以打印3张,但至少它很简单,可以做你想要的。 the do while(0) trick makes sure this is one only block (when using if without braces) and requires semicolon. do while(0)招确保(使用时,这是一个只有块if没有大括号),需要分号。

If you're willing to rely on the first argument to LogPrintf being a string literal, then you should be able to use string concatenation to achieve your objective: 如果您愿意依赖LogPrintf的第一个参数是字符串文字,那么您应该能够使用字符串连接来实现您的目标:

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

Note, however, that in standard C, the LogPrintf macro requires at least two arguments, and the ## has no place. 但请注意,在标准C中, LogPrintf宏至少需要两个参数,并且##没有位置。 I keep it here only because you use it in your original code. 我保留在这里只是因为你在原始代码中使用它。

If you must accept format string expressions other than string literals, however, then your simplest alternative is to perform multiple I/O calls, as another answer also suggests: 但是,如果必须接受除字符串文字之外的格式字符串表达式,那么最简单的替代方法是执行多个I / O调用,另一个答案也表明:

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

Note that in this case, the macro expands to a statement (sans trailing semicolon), whereas in the other, the macro expands to an expression . 请注意,在这种情况下,宏会扩展为一个语句 (没有分号),而在另一个中,宏会扩展为一个表达式 If you want the return value(s) of any of the I/O functions, then you'll have to make special provisions for that in this case. 如果您想要任何I / O函数的返回值,那么在这种情况下您必须为此做出特殊规定。

If that doesn't work for you either, then the ultimate alternative is to write and use a helper function, as was suggested in comments: 如果这对你也不起作用,那么最终的选择是编写和使用辅助函数,如评论中所建议的那样:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM