【问题标题】:Is it safe to pass a va_list to another function without using va_copy?在不使用 va_copy 的情况下将 va_list 传递给另一个函数是否安全?
【发布时间】:2015-01-13 05:16:22
【问题描述】:

This blog post 声称将va_list 传递给下面代码中的另一个函数是不安全的,并且必须首先使用va_copy 复制va_list

void
foo_ap(const char *fmt, va_list ap)
{
    char buf[128];

    vsnprintf(buf, sizeof(buf), fmt, ap);

    // now, do something with buf ...
}

就像博客文章中提到的其中一位 cmets 一样,我看不出这有多不安全,正如 C99 规范所述 (7.15):

对象ap 可以作为参数传递给另一个函数;如果该函数调用带有参数apva_arg 宏,则调用函数中ap 的值是不确定的,应在进一步引用ap 之前将其传递给va_end 宏。

(只要foo_ap 在传递它之后不引用ap,这句话的第二部分似乎无论如何都不适用。)博客文章的作者在另一条评论中说他可能错了,但也许有人可以添加一些说明。为了安全起见,我真的必须使用va_copy 吗?或者有没有平台不符合规范,需要使用va_copy

【问题讨论】:

  • 这篇博文似乎与您从 C9​​9 标准中引用的条款直接矛盾。博客作者确实在开头说“很久以前”,所以我猜他正在处理一些旧的、不符合标准的系统。
  • 如果您在vsnprintf 返回后仍打算使用ap,则只需要va_copy。例如,您可能想要调用vsnprintf 两次——一次确定所需的缓冲区大小,然后再次进行格式化。如果你不需要再次使用ap,除了将它传递给va_end,那么你不需要va_copy它。
  • @IgorTandetnik 如果您将您的评论作为答案,我会接受。

标签: c language-lawyer c99 variadic-functions


【解决方案1】:

如果您仍打算在vsnprintf 返回后使用ap,则只需要va_copy。例如,您可能想要调用vsnprintf 两次——一次是为了确定所需的缓冲区大小,另一次是为了真正格式化。如果您不需要再次使用ap(可能除了将其传递给va_end,如果您是使用va_start 创建它的人),那么您不需要va_copy 它。

【讨论】:

  • 我观察到 va_list 表现得好像按值传递的实现 [因此,接收它的函数所消耗的参数在该函数返回时重新存在],以及其他表现得好像传递的实现通过引用[参数仍然被消耗]。因此,在调用也使用它的方法后使用 va_list 的问题不仅仅是“理论上的”。
猜你喜欢
  • 1970-01-01
  • 2021-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多