我有一个函数,试图将东西记录到控制台和日志文件,但它不起作用。第二次使用可变长度参数会将垃圾写入控制台。有任何想法吗?
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);
}
原始代码失败,因为它试图使用 printf()
需要使用的地方 vprintf()
。采取可疑的点,如 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_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
和一个封面函数,它接受省略号(变量参数)并在转换为a后将它们传递给操作函数 va_list
- 通常是一种很好的工作方式。迟早,你通常会发现需要带有的版本 va_list
论据。
升级你的编译器,更像是C ++:
template <typename... Args>
void logPrintf(const char *fmt, Args&&... args) {
logOpen;
fprintf(flog, fmt, args...);
logClose;
printf(fmt, args...);
}
虽然当然提供类型安全版本会很好 printf
和 fprintf
。
我认为这种方式更有意义:
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);
}