原始代码失败是因为它试图printf()在需要使用的地方使用vprintf()。logOpen从表面上看像and语句这样的可疑点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()在其他情况下,例如当您的函数传递 ava_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_copyargs1va_endargs1va_endargs2
该logPrintf()功能可以按照logVprintf()现在来实现:
void logPrintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
logVprintf(fmt, args);
va_end(args);
}
这种结构——一个接受 a 的操作函数va_list和一个接受省略号(变量参数)并在转换为 a 后将它们传递给操作函数的覆盖函数va_list——通常是一种很好的工作方式。迟早,您通常会发现需要带有va_list参数的版本。