Исходный код не работает, потому что он пытается использовать printf()
там, где ему нужно использовать vprintf()
.Принимая сомнительные точки, такие как операторы logOpen
и logClose
по номинальной стоимости (учитывая обозначения, предположительно, они являются макросами, которые открывают и закрывают поток файлов flog
), код должен быть:1008 * Нет особого требования использовать две отдельные va_list
переменные;вполне нормально использовать один и тот же дважды , если вы используете va_end()
, прежде чем снова использовать va_start()
.
void logPrintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
logOpen;
vfprintf(flog, fmt, ap);
logClose;
va_end(ap);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
Когда значение va_list
передается вдругая функция (vfprintf()
и vprintf()
в этом коде), вы должны предположить, что она больше не может использоваться в текущей функции.На него можно только позвонить va_end()
.
В этом коде нет необходимости вводить va_copy()
.Это работает, но это не нужно.Вам нужно va_copy()
в других обстоятельствах, например, когда вашей функции передается va_list
, и вам нужно дважды обработать список:
void logVprintf(const char *fmt, va_list args1)
{
va_list args2;
va_copy(args2, args1);
logOpen;
vfprintf(flog, fmt, args1);
logClose;
vprintf(fmt, args2);
va_end(args2);
}
Обратите внимание, что в этом коде это ответственность вызывающего кодапозвонить va_end()
на args1
.Действительно, стандарт гласит:
Каждый вызов макросов va_start
и va_copy
должен сопоставляться с соответствующим вызовом макроса va_end
в той же функции.
Поскольку функция logVprintf()
не вызывает ни va_start
, ни va_copy
для инициализации args1
, она не может законно вызвать va_end
для args1
.С другой стороны, стандарт требует, чтобы он вызывал va_end
для args2
.
Функция logPrintf()
может быть реализована в виде logVprintf()
сейчас:
void logPrintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
logVprintf(fmt, args);
va_end(args);
}
Эта структура - операционная функция, которая принимает va_list
и функция покрытия, которая принимает многоточие (переменные аргументы) и передает их в операционную функцию после преобразования в va_list
- часто является хорошим способом работы.Рано или поздно вам обычно требуется версия с аргументом va_list
.