重复使用可变参数函数参数不起作用
我有一个函数尝试将内容记录到控制台和日志文件中,但它不起作用。第二次使用可变长度参数会将垃圾写入控制台。有什么想法吗?
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);
}
I have a function that tries to log stuff to the console and also to a log file, but it doesn't work. The second use of the variable length argument gives garbage written to the console. Any ideas?
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
原始代码失败,因为它尝试在需要使用
vprintf()
的地方使用printf()
。从表面上看像logOpen
和logClose
语句这样的可疑点(根据符号,大概它们是打开和关闭flog
文件的宏流),代码应该是:使用两个单独的
va_list
变量没有特殊要求; 在再次使用va_start()
之前使用va_end()
,就可以使用同一个函数两次。只要 code>va_list 值传递给另一个函数(此代码中的
vfprintf()
和vprintf()
),您应该假设它不再可用当前函数。只有调用va_end()
才是安全的。此代码中不需要
va_copy()
。它有效,但不需要。在其他情况下,您需要va_copy()
,例如当您的函数传递va_list
时,您需要处理该列表两次:请注意,在此代码中,它是调用代码的责任是在
args1
上调用va_end()
。事实上,该标准说:由于
logVprintf()
函数不会调用va_start
或va_copy
来初始化args1
,因此它无法合法调用args1
上的va_end
。另一方面,标准要求它为args2
调用va_end
。logPrintf()
函数现在可以用logVprintf()
来实现:此结构 — 一个带有
va_list
和 cover 的操作函数采用省略号(变量参数)并在转换为 va_list 后将它们传递给操作函数的函数 — 通常是一种很好的工作方式。迟早,您通常会发现需要带有va_list
参数的版本。The original code fails because it tries to use
printf()
where it needs to usevprintf()
. Taking dubious points like thelogOpen
andlogClose
statements at face value (given the notation, presumably they're macros which open and close theflog
file stream), the code should be:There's no particular requirement to use two separate
va_list
variables; it is perfectly OK to use the same one twice as long as you useva_end()
before you useva_start()
again.When a
va_list
value is passed to another function (vfprintf()
andvprintf()
in this code), you should assume that it is no longer usable in the current function. It is only safe to callva_end()
on it.There is no need for
va_copy()
in this code. It works, but it isn't needed. You needva_copy()
in other circumstances, such as when your function is passed ava_list
and you need to process the list twice:Note that in this code, it is the calling code's responsibility to call
va_end()
onargs1
. Indeed, the standard says:Since the
logVprintf()
function doesn't call eitherva_start
orva_copy
to initializeargs1
, it cannot legitimately callva_end
onargs1
. On the other hand, the standard requires it to callva_end
forargs2
.The
logPrintf()
function can be implemented in terms oflogVprintf()
now:This structure — an operational function that takes a
va_list
and a cover function that takes ellipsis (variable arguments) and passes them to the operational function after conversion to ava_list
— is often a good way to work. Sooner or later, you usually find a need for the version with ava_list
argument.升级你的编译器,这更像是 C++:
当然,提供
printf
和fprintf
的类型安全版本会更好。Upgrade your compiler, that is more like C++:
Though of course it would then be good taste to provide typesafe versions of
printf
andfprintf
.我认为这种方式更有意义:
I think this way makes more sense: