我有一个功能,试图将东西记录到控制台和日志文件,但它不起作用.第二次使用可变长度参数给垃圾写入控制台.有任何想法吗?
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,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,ap); logClose; va_end(ap); va_start(ap,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,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参数的版本.