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

发布于 2025-01-06 03:34:05 字数 413 浏览 0 评论 0原文

我有一个函数尝试将内容记录到控制台和日志文件中,但它不起作用。第二次使用可变长度参数会将垃圾写入控制台。有什么想法吗?

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

I have a function that tries to log stuff to the console and also to a log file, but it doesn't work. The second use of the variable length argument gives garbage written to the console. Any ideas?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无需解释 2025-01-13 03:34:05

原始代码失败,因为它尝试在需要使用 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);
}

只要 code>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()。事实上,该标准说:

每次调用 va_startva_copy
应与同一函数中 va_end 宏的相应调用相匹配。

由于 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 和 cover 的操作函数采用省略号(变量参数)并在转换为 va_list 后将它们传递给操作函数的函数 — 通常是一种很好的工作方式。迟早,您通常会发现需要带有 va_list 参数的版本。

The original code fails because it tries to use printf() where it needs to use vprintf(). Taking dubious points like the logOpen and logClose statements at face value (given the notation, presumably they're macros which open and close the flog file stream), the code should be:

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

There's no particular requirement to use two separate va_list variables; it is perfectly OK to use the same one twice as long as you use va_end() before you use va_start() again.

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

When a va_list value is passed to another function (vfprintf() and vprintf() in this code), you should assume that it is no longer usable in the current function. It is only safe to call va_end() on it.

There is no need for va_copy() in this code. It works, but it isn't needed. You need va_copy() in other circumstances, such as when your function is passed a va_list and you need to process the list twice:

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

Note that in this code, it is the calling code's responsibility to call va_end() on args1. Indeed, the standard says:

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.

Since the logVprintf() function doesn't call either va_start or va_copy to initialize args1, it cannot legitimately call va_end on args1. On the other hand, the standard requires it to call va_end for args2.

The logPrintf() function can be implemented in terms of logVprintf() now:

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

This structure — an operational function that takes a va_list and a cover function that takes ellipsis (variable arguments) and passes them to the operational function after conversion to a va_list — is often a good way to work. Sooner or later, you usually find a need for the version with a va_list argument.

策马西风 2025-01-13 03:34:05

升级你的编译器,这更像是 C++:

template <typename... Args>
void logPrintf(const char *fmt, Args&&... args) {
    logOpen;
    fprintf(flog, fmt, args...);
    logClose;

    printf(fmt, args...);
}

当然,提供 printffprintf 的类型安全版本会更好。

Upgrade your compiler, that is more like C++:

template <typename... Args>
void logPrintf(const char *fmt, Args&&... args) {
    logOpen;
    fprintf(flog, fmt, args...);
    logClose;

    printf(fmt, args...);
}

Though of course it would then be good taste to provide typesafe versions of printf and fprintf.

瑶笙 2025-01-13 03:34:05

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

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

I think this way makes more sense:

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);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文