重复使用可变参数函数参数不起作用

Ned*_*die 13 c c++ variadic variadic-functions

我有一个函数,试图将东西记录到控制台和日志文件,但它不起作用.第二次使用变长参数会将垃圾写入控制台.有任何想法吗?

    void logPrintf(const char *fmt, ...) {
        va_list ap;    // log to logfile
        va_start(ap, fmt);
        logOpen;
        vfprintf(flog, fmt, ap);
        logClose;
        va_end(ap);
        va_list ap2;   // log to console
        va_start(ap2, fmt);
        printf(fmt, ap2);
        va_end(ap2);
    }
Run Code Online (Sandbox Code Playgroud)

Jon*_*ler 12

原始代码失败,因为它尝试使用printf()它需要使用的位置vprintf().采用像面部值logOpenlogClose语句一样的可疑点(给出符号,可能是它们是打开和关闭flog文件流的宏),代码应该是:

void logPrintf(const char *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    logOpen;
    vfprintf(flog, fmt, ap);
    logClose;
    va_end(ap);
    va_list ap2;
    va_start(ap2, fmt);
    vprintf(fmt, ap2);
    va_end(ap2);
}
Run Code Online (Sandbox Code Playgroud)

没有特别要求使用两个单独的va_list变量; 再次使用之前,使用相同的两倍是完全可以的.va_end()va_start()

void logPrintf(const char *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    logOpen;
    vfprintf(flog, fmt, ap);
    logClose;
    va_end(ap);
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
}
Run Code Online (Sandbox Code Playgroud)

当一个va_list值传递给另一个函数(vfprintf()vprintf()在此代码中)时,您应该假定它在当前函数中不再可用.打电话是安全的va_end().

va_copy()此代码中没有必要.它有效,但不需要.您需要va_copy()在其他情况下,当你的函数传递一个如va_list你需要处理列表两次:

void logVprintf(const char *fmt, va_list args1)
{
    va_list args2;
    va_copy(args2, args1);
    logOpen;
    vfprintf(flog, fmt, args1);
    logClose;
    vprintf(fmt, args2);
    va_end(args2);
}
Run Code Online (Sandbox Code Playgroud)

请注意,在这段代码,它是调用代码的责任调用va_end()args1.的确,标准说:

每次调用va_startva_copy宏都应该通过va_end相同函数中宏的相应调用来匹配.

由于该logVprintf()功能不调用任何va_startva_copy初始化args1,就不能合法地调用va_endargs1.在另一方面,标准要求它打电话va_endargs2.

logPrintf()功能现在可以实现logVprintf():

void logPrintf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    logVprintf(fmt, args);
    va_end(args);
}
Run Code Online (Sandbox Code Playgroud)

这个结构 - 一个操作函数,它接受一个va_list带有省略号(变量参数)的覆盖函数,并在转换为va_list- 后将它们传递给操作函数,这通常是一种很好的工作方式.迟早,您通常会发现需要带有va_list参数的版本.

  • 这是正确的答案,直接解决OP的问题,而不建议改变他们的架构. (2认同)

Ton*_*ion -2

我认为这种方式更有意义:

void logPrintf(const char *fmt, ...) {
        va_list ap;    // log to logfile
        va_start(ap, fmt);
        logOpen;
        vfprintf(flog, fmt, ap); //logfile
         printf(fmt, ap); //console
        logClose;
        va_end(ap);
    }
Run Code Online (Sandbox Code Playgroud)