首页 > 解决方案 > 使用 vsnprintf 时有没有办法绕过 va_copy?

问题描述

我在一个旧的嵌入式平台上引入了一个 3rd 方协议栈,除了 va_copy 之外,所有的 va_* 东西都被实现了。我面临的问题是,在第 3 方堆栈中,使用了 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);
  }  
}  

幸运的是,第 3 方堆栈证明了它自己的 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(). 我假设 (va_list) ap 的内部指针指向错误的内存地址。那么如何纠正呢?

标签: c

解决方案


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

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

似乎在具有固定参数的函数中调用它们会导致未定义的行为,幸运的是第一次调用vsnprintf实际上是有效的。

由于您没有va_arg在内部调用不应该改变fun的值,ap因此您应该能够根据需要调用任意vsnprintf多次。


推荐阅读