我有一个函数尝试将内容记录到控制台以及日志文件中,但它不起作用。第二次使用变长参数会将垃圾写入控制台。有任何想法吗?
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);
}
答案 0 :(得分:11)
原始代码失败,因为它尝试在需要printf()
的地方使用vprintf()
。将logOpen
和logClose
语句等可疑点视为面值(给定符号,可能是它们是打开和关闭flog
文件流的宏),代码应为:< / p>
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_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);
}
当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);
}
请注意,在此代码中,调用代码有责任在va_end()
上调用args1
。的确,标准说:
每次调用
va_start
和va_copy
宏 应与相同函数中va_end
宏的相应调用相匹配。
由于logVprintf()
功能无法调用va_start
或va_copy
来初始化args1
,因此无法在va_end
上合法调用args1
。另一方面,该标准要求它为va_end
调用args2
。
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
参数的版本。
答案 1 :(得分:2)
升级您的编译器,更像是C ++:
template <typename... Args>
void logPrintf(const char *fmt, Args&&... args) {
logOpen;
fprintf(flog, fmt, args...);
logClose;
printf(fmt, args...);
}
虽然提供printf
和fprintf
的类型安全版本当然是个好品味。
答案 2 :(得分:-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);
}