代码之家  ›  专栏  ›  技术社区  ›  feng

在使用vsnprintf时,有没有办法绕过va_copy?

c
  •  3
  • feng  · 技术社区  · 7 年前

    我将在一个旧的嵌入式平台上介绍一个第三方协议栈,在这个平台上,除了虚拟拷贝之外,所有虚拟内容都实现了。我面临的问题是,在第三方堆栈中,使用了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);
      }  
    }   
    

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

    2 回复  |  直到 7 年前
        1
  •  1
  •   gabry    7 年前

    如果您的平台像大多数平台一样有一个简单的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);
      }  
    }   
    
        2
  •  1
  •   Chris Turner    7 年前

    你也不应该打电话 va_start va_end fun . 只应在具有 ... 在参数列表中指示参数的数目可变。我的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);
    

    vsnprintf 实际上是在工作。

    va_arg 里面 乐趣 ap 不应该改变你应该可以打电话 vsnprintf公司