我有一个函数,试图将东西记录到控制台和日志文件,但它不起作用。第二次使用可变长度参数会将垃圾写入控制台。有任何想法吗?
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);
}