我有一个尝试将内容记录到控制台和日志文件的函数,但它不起作用。可变长度参数的第二次使用会将垃圾写入控制台。有任何想法吗?
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()
。从表面上看像 logOpen
和 logClose
语句这样的可疑点(给定符号,大概它们是打开和关闭 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
andva_copy
macros shall be matched by a corresponding invocation of theva_end
macro in the same function.
由于 logVprintf()
函数不调用 va_start
或 va_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/