В качестве альтернативы использованию va_copy()
- в соответствии с предложением Дитрих Эпп в ответе - вы можете просто использовать va_start()
и va_end()
дважды.
void myself_printf(char *key_fmt, char *value_fmt, ...)
{
char real_key[1024];
char real_value[1024];
va_list args;
va_start(args, value);
vsnprintf(real_key, sizeof(real_key), key_fmt, args);
va_end(args);
vs_start(args, value);
vsnprintf(real_value, sizeof(real_key), value_fmt, args);
va_end(args);
…do something useful with real_key and real_value…
}
Исходная версия вопроса использовалась char real_key[1024000];
и аналогично для real_value
. Выделение почти 2 МБ данных в стеке не будет надежно работать в Windows (ограничение обычно составляет 1 МБ стека) и занимает очень много места в системах Unix (где размер стека обычно составляет 8 МБ). Будьте осторожны!
Вам нужно будет использовать va_copy()
, если va_list
был передан в качестве аргумента вашей функции. Например:
void myself_printf(char* key, char* value, ...)
{
va_list args;
va_start(args, value);
myself_vprintf(key, value, args);
va_end(args);
}
void myself_vprintf(char *key_fmt, char *value_fmt, va_list args1)
{
char real_key[1024];
char real_value[1024];
va_list args2;
va_copy(args2, args1);
vsnprintf(real_key, sizeof(real_key), key_fmt, args1);
vsnprintf(real_value, sizeof(real_value), value_fmt, args2);
va_end(args2);
…do something useful with real_key and real_value…
}
Спецификация va_end()
гласит:
Макрос va_end
облегчает нормальный возврат из функции, чей список переменных-переменных был упомянут расширением макроса va_start
, или функции, содержащей расширение макроса va_copy
, которая инициализировала va_list ap
. Макрос va_end
может изменить ap
, чтобы он больше не мог использоваться (без повторной инициализации макросом va_start
или va_copy
). Если нет соответствующего вызова макроса va_start
или va_copy
, или если макрос va_end
не вызывается до возврата, поведение не определено.
Обратите внимание, что спецификация функции vfprintf()
включает сноску 288 , которая гласит:
Поскольку функции vfprintf
, vfscanf
, vprintf
, vscanf
, vsnprintf
, vsprintf
и vsscanf
вызывают макрос va_arg
, значение arg
после возврата является неопределенным.
Конечно, сноски не являются нормативными, но это явный признак того, что функции, как ожидается, будут использовать va_arg
, и, следовательно, двойное использование arg
, как показано в вопросе, приводит к неопределенному поведению, если нет промежуточного вызова на va_end
и другое va_start
или использование va_copy
(и его соответствие va_end
).