va_copy -- 移植到 Visual C++?

问题描述 投票:0回答:4

上一个问题展示了一种打印字符串的好方法。答案涉及

va_copy

std::string format (const char *fmt, ...);
{
   va_list ap;
   va_start (ap, fmt);
   std::string buf = vformat (fmt, ap);
   va_end (ap);
   return buf;
}


std::string vformat (const char *fmt, va_list ap)
{
   // Allocate a buffer on the stack that's big enough for us almost
   // all the time.
   s ize_t size = 1024;
   char buf[size];

   // Try to vsnprintf into our buffer.
   va_list apcopy;
   va_copy (apcopy, ap);
   int needed = vsnprintf (&buf[0], size, fmt, ap);

   if (needed <= size) {
       // It fit fine the first time, we're done.
       return std::string (&buf[0]);
   } else {
       // vsnprintf reported that it wanted to write more characters
       // than we allotted.  So do a malloc of the right size and try again.
       // This doesn't happen very often if we chose our initial size
       // well.
       std::vector <char> buf;
       size = needed;
       buf.resize (size);
       needed = vsnprintf (&buf[0], size, fmt, apcopy);
       return std::string (&buf[0]);
   }
}

我遇到的问题是上面的代码无法移植到 Visual C++,因为它不提供

va_copy
(甚至
__va_copy
)。那么,有谁知道如何安全地移植上述代码?据推测,我需要做一个
va_copy
副本,因为
vsnprintf
破坏性地修改了传递的
va_list

c++ c visual-studio-2008 visual-c++
4个回答
14
投票

您应该能够只做常规作业就可以逃脱:

va_list apcopy = ap;

从技术上讲,它是不可移植和未定义的行为,但它适用于大多数编译器和体系结构。 在 x86 调用约定中,

va_list
只是指向堆栈的指针,可以安全地复制。


10
投票

对于Windows,您可以简单地自己定义va_copy:

#define va_copy(dest, src) (dest = src)

5
投票

您可以做的一件事是,如果您不需要

vformat()
函数,请将其实现移至
format()
函数(未经测试):

#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <string>
#include <vector>


std::string format(const char *fmt, ...)
{
   va_list ap;

   enum {size = 1024};

   // if you want a buffer on the stack for the 99% of the time case 
   //   for efficiency or whatever), I suggest something like
   //   STLSoft's auto_buffer<> template.
   //
   //   http://www.synesis.com.au/software/stlsoft/doc-1.9/classstlsoft_1_1auto__buffer.html
   //
   std::vector<char> buf( size);

   //
   // where you get a proper vsnprintf() for MSVC is another problem
   // maybe look at http://www.jhweiss.de/software/snprintf.html
   //

   // note that vsnprintf() might use the passed ap with the 
   //   va_arg() macro.  This would invalidate ap here, so we 
   //   we va_end() it here, and have to redo the va_start()
   //   if we want to use it again. From the C standard:
   //
   //       The object ap may be passed as an argument to
   //       another function; if that function invokes the 
   //       va_arg macro with parameter ap, the value of ap 
   //       in the calling function is indeterminate and 
   //       shall be passed to the va_end macro prior to 
   //       any further reference to ap.   
   //
   //    Thanks to Rob Kennedy for pointing that out.
   //
   va_start (ap, fmt);
   int needed = vsnprintf (&buf[0], buf.size(), fmt, ap);
   va_end( ap);

   if (needed >= size) {
       // vsnprintf reported that it wanted to write more characters
       // than we allotted.  So do a malloc of the right size and try again.
       // This doesn't happen very often if we chose our initial size
       // well.
       buf.resize( needed + 1);

       va_start (ap, fmt);
       needed = vsnprintf (&buf[0], buf.size(), fmt, ap);
       va_end( ap);

       assert( needed < buf.size());
   }

   return std::string( &buf[0]);
}

3
投票

Visual Studio 2013

 开始直接支持 
va_copy()。因此,如果您可以信赖它的可用性,则无需执行任何操作。

© www.soinside.com 2019 - 2024. All rights reserved.