va_copy — porting to visual C++?

前端 未结 4 910
不思量自难忘°
不思量自难忘° 2020-12-15 19:35

A previous question showed a nice way of printing to a string. The answer involved va_copy:

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


        
相关标签:
4条回答
  • 2020-12-15 20:15

    One thing you can do is if you do not otherwise need the vformat() function, move its implementation into the format() function (untested):

    #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]);
    }
    
    0 讨论(0)
  • 2020-12-15 20:22

    You should be able to get away with just doing a regular assignment:

    va_list apcopy = ap;
    

    It's technically non-portable and undefined behavior, but it will work with most compilers and architectures. In the x86 calling convention, va_lists are just pointers into the stack and are safe to copy.

    0 讨论(0)
  • 2020-12-15 20:22

    va_copy() is directly supported starting in Visual Studio 2013. So if you can rely on that being available, you don't need to do anything.

    0 讨论(0)
  • 2020-12-15 20:32

    For Windows, you can simply define va_copy yourself:

    #define va_copy(dest, src) (dest = src)
    
    0 讨论(0)
提交回复
热议问题