原始代码失败是因为它试图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_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);
}
这种结构——一个接受 a 的操作函数va_list
和一个接受省略号(变量参数)并在转换为 a 后将它们传递给操作函数的覆盖函数va_list
——通常是一种很好的工作方式。迟早,您通常会发现需要带有va_list
参数的版本。