va_copy – 移植到Visual C ++?

之前的一个问题显示了一种打印到字符串的好方法。 答案涉及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  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。

你应该能够通过定期任务逃脱:

 va_list apcopy = ap; 

它在技术上是不可移植和未定义的行为,但它适用于大多数编译器和体系结构。 在x86调用约定中, va_list只是指向堆栈的指针,可以安全地复制。

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

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

你可以做的一件事是,如果你不需要vformat()函数,将其实现移动到format()函数(未经测试):

 #include  #include  #include  #include  #include  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 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]); } 

从Visual Studio 2013开始直接支持va_copy() 。 因此,如果您可以依赖可用,则无需执行任何操作。