x64 x32 visual sp1 microsoft descargar c++ c visual-studio-2008 visual-c++

x32 - va_copy-porting a visual C++?



microsoft visual c++ 2012 (4)

Una pregunta anterior mostró una buena forma de imprimir en una cadena. La respuesta involucró 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]); }

}

El problema que tengo es que el código anterior no se transfiere a Visual C ++ porque no proporciona va_copy (o incluso __va_copy). Entonces, ¿alguien sabe cómo portar con seguridad el código anterior? Presumiblemente, necesito hacer una copia de va_copy porque vsnprintf modifica de forma destructiva la va_va_list pasada.


Debería poder salirse con la suya simplemente haciendo una tarea regular:

va_list apcopy = ap;

Es un comportamiento técnicamente no portátil e indefinido, pero funcionará con la mayoría de los compiladores y arquitecturas. En la convención de llamadas x86, va_list s son solo punteros en la pila y son seguros de copiar.


Una cosa que puede hacer es si no necesita la función vformat() , mueva su implementación a la función format() (no probada):

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


Para Windows, simplemente puede definir va_copy usted mismo:

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


va_copy() se admite directamente a partir de Visual Studio 2013 . Entonces, si puedes confiar en que esté disponible, no necesitas hacer nada.