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

标签 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);
    }

最佳答案

原始代码失败,因为它尝试在需要使用 vprintf() 的地方使用 printf()。从表面上看像 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);
}

没有特别要求使用两个单独的 va_list 变量;只要您在再次使用 va_start() 之前使用 va_end(),就可以使用相同的两次

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

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

请注意,在此代码中,调用代码负责在 args1 上调用 va_end()。确实,标准说:

Each invocation of the va_start and va_copy macros shall be matched by a corresponding invocation of the va_end macro in the same function.

由于 logVprintf() 函数不调用 va_startva_copy 来初始化 args1,它不能在 args1 上合法地调用 va_end。另一方面,标准要求它为 args2 调用 va_end

logPrintf()函数现在可以用logVprintf()来实现了:

void logPrintf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    logVprintf(fmt, args);
    va_end(args);
}

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

关于c++ - 重复使用可变参数函数参数不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9309246/

相关文章:

c++ - 从字节中获取位

c - 为什么时间在 IPC 的代码中打印相同

c++ - 嵌套的大括号括起来的初始化列表

c++ - 根据进程 ID 确定进程是否存在

C++ - 方法实现取决于是否设置了成员引用变量

android - 使用 JNI 通过 UNIX 域套接字发送 Java FD

c++ - 为什么要创建 GObject 系统?

c++ - 用C和C++调用的(…)是什么?

c++ - 可变参数扩展可以用作逗号运算符调用链吗?

c++ - 为什么我需要做 'using namespace std' 而不是 'using std::cout' ?