Предполагается, что va_copy () является частью спецификации C99; как и для всех переменных, поддержка параметров очень зависит от платформы. Макросы va_list, va_copy (), va_start (), va_end () определены в stdarg.h .
GCC: при попытке повторно использовать va_list в GCC, один ДОЛЖЕН использовать va_copy (), так как реализация GCC вызывает изменение va_list, в результате чего указатель позиционируется после последнего параметра после использования av ?? printf () функция.
СОЛНЦЕ: При попытке повторно использовать va_list в SunStudio (v11, v12) переменная va_list не затрагивается и может использоваться повторно столько раз, сколько необходимо, без необходимости va_copy ().
MS_Visual C: Не уверен, но похоже, что в документах VC ++ 2010 года упоминается 'va_copy ()' и может подразумеваться, что повторное использование va_list является разумным, но должно быть проверено.
Пример:
#include <stdio.h>
#include <stdarg.h>
/**
* Version of vsprintf that dynamically resizes the given buffer to avoid overrun.
* Uses va_copy() under GCC compile.
**/
int my_vsprintf(char **buffer, char *msg, va_list args)
{
int bufLen = 0;
va_list dupArgs; // localize args copy
#ifdef __GNUC__
va_copy(dupArgs,args); // Clone arguments for reuse by different call to vsprintf.
#else
dupArgs = args; // Simply ptr copy for GCC compatibility
#endif
// Perform 1st pass to calculate required buffer size. The vsnprintf() funct
// returns the number of chars (excluding \0 term) necessary to produce the output.
// Notice the NULL pointer, and zero length.
bufLen = vsnprintf(NULL,0,msg, dupArgs);
// NOTE: dupArgs on GCC platform is mangled by usage in v*printf() and cannot be reused.
#ifdef __GNUC__
va_end(dupArgs); // cleanup
#endif
*buffer = realloc(*buffer,bufLen + 1); // resize buffer, with \0 term included.
#ifdef __GNUC__
va_copy(dupArgs,args); // Clone arguments for reused by different call to vsprintf.
#endif
// Perform 2nd pass to populate buffer that is sufficient in size,
// with \0 term size included.
bufLen = vsnprintf(buffer, bufLen+1, msg, dupArgs);
// NOTE: dupArgs on GCC platform is mangled by usage in v*printf() and cannot be reused.
#ifdef __GNUC__
va_end(dupArgs); // cleanup
#endif
return(bufLen); // return chars written to buffer.
}
/**
* Version of sprintf that dynamically resizes the given buffer to avoid buffer overrun
* by simply calling my_vsprintf() with the va_list of arguments.
*
* USage:
**/
int my_sprintf(char **buffer, char *msg, ...)
{
int bufLen = 0;
va_list myArgs;
va_start(myArgs, msg); // Initialize myArgs to first variadic parameter.
// re-use function that takes va_list of arguments.
bufLen = my_vsprintf(buffer, msg, myArgs );
va_end(myArgs);
}