使用vsnprintf时是否可以绕过va_copy?

时间:2018-09-03 08:01:13

标签: c

我要在旧的嵌入式平台上引入第3方协议栈,在该平台上,除了va_copy之外,所有va_ *东西都已实现。我面临的问题是,在第三方堆栈中,使用了vsnprintf():

int fun(char **buf, size_t buf_size, const char *fmt, va_list ap) {
  va_list ap_copy;
  int len;
  /* first call*/
  va_copy(ap_copy, ap);
  len = vsnprintf(*buf, buf_size, fmt, ap_copy);
  va_end(ap_copy);
  if(len >= buf_size)
  {
      /* 2nd call*/
      va_copy(ap_copy, ap);
      len = vsnprintf(*buf, len + 1, fmt, ap_copy);
      va_end(ap_copy);
  }  
}  

幸运的是,第三方堆栈证明了自己的vsnprintf函数(称为new_vsnprintf),但是如果没有va_copy,则只有第一个调用起作用,即,当len小于buf_size时。下面是我的称呼方式:

#define vsnprintf new_vsnprintf
int fun(char **buf, size_t buf_size, const char *fmt, va_list ap) {
  //va_list ap_copy;
  int len;
  /* first call*/
  va_start(ap, fmt);
  len = vsnprintf(*buf, buf_size, fmt, ap);
  va_end(ap);
  if(len >= buf_size)
  {
      /* 2nd call*/
      va_start(ap, fmt);
      len = vsnprintf(*buf, len + 1, fmt, ap);  //new_vsnprintf()
      va_end(ap);
  }  
}   

尝试通过va_arg()获取占位符的实际值时,在new_vsnprintf()的第二次调用中出现问题。我假设(va_list)ap的内部指针指向错误的内存地址。 那么如何纠正呢?

2 个答案:

答案 0 :(得分:1)

如果您的平台像大多数平台一样具有简单的varargs处理,则此答案可能有用。如果您的平台不允许简单复制va_list对象,则此操作将无效。在大多数平台上,va_copy是一个简单的宏,其功能类似于:

#define va_copy(dest, src) dest = src

... x86,ppc和许多其他目标就是这种情况。无论如何,这里是代码,我希望它能工作,在不知道您使用它的平台的情况下,我无法测试或确认它能工作!

int fun(char **buf, size_t buf_size, const char *fmt, va_list ap) {
  va_list ap_copy = ap;
  int len;
  /* first call*/
  va_start(ap_copy, fmt);
  len = vsnprintf(*buf, buf_size, fmt, ap_copy);
  va_end(ap_copy);
  if(len >= buf_size)
  {
      /* 2nd call*/
      va_start(ap, fmt);
      len = vsnprintf(*buf, len + 1, fmt, ap);  //new_vsnprintf()
      va_end(ap);
  }  
}   

答案 1 :(得分:1)

您不应在函数va_start中调用va_endfun。仅应在参数列表中具有...的函数中调用它们,以指示参数数量可变。如果我尝试编译当前存在的代码,我的gcc版本(4.8.4)甚至会引发错误。

test.c: In function ‘fun’:
test.c:14:3: error: ‘va_start’ used in function with fixed args
   va_start(ap, fmt);

在带有固定args的函数中调用它们似乎导致未定义的行为,很幸运的是,对vsnprintf的第一次调用确实有效。

由于您没有在va_arg内部调用fun,因此ap的值不应更改,并且您应该可以多次调用vsnprintf要求。