Я пытаюсь написать вариант printf, где печатаемый элемент и печатаемый формат являются смежными параметрами в вызове типа...
print(2, "%s", "hello", "%.5u", 25);
Я изучил на var args и придумал....
void print(int count, ...)
{
va_list varg;
va_start(varg, count);
while(count-- > 0)
{
char* format = va_arg(varg, char*);
vprintf(format, varg);
}
va_end(varg);
}
Похоже, что vprintf не потребляет элемент, который он использует из стека. Мой вывод
Привет привет
Я считаю, что это тоже расширяется
printf("%s", "hello);
printf("hello");
Итак, что я делаю неправильно, что vprintf не потребляет "привет" из списка arg?
Обновление: за комментарий ниже
void print(int count, ...)
{
va_list varg;
va_start(varg, count);
while(count-- > 0)
{
char* format = va_arg(varg, char*);
void* arg = va_arg(varg, void*);
printf(format, arg);
}
va_end(varg);
}
Кажется, что эта работа выполнена.
Va_list - это не что иное, как адрес (в типичных реализациях). Он передается по значению функции, поэтому оригинал в вызывающей функции не модифицируется.
То, что вы здесь делаете, - это неопределенное поведение. В стандарте C99, раздел 7.15, пункт 3, говорится:
Объявленный тип - это
va_list
который является типом объекта, подходящим для хранения информации, необходимой для макросовva_start
,va_arg
,va_end
иva_copy
. Если требуется доступ к переменным аргументам, вызываемая функция объявляет объект (обычно называемыйap
в этом подпункте), имеющий типva_list
. Объектap
может передаваться как аргумент другой функции; если эта функция вызывает макросva_arg
с параметромap
, значениеap
в вызывающей функции является неопределенным и должно быть передано макросуva_end
до любой дополнительной ссылки наap
.
Здесь вы передаете переменную va_list
varg
в функцию vprintf
, которая вызывает внутри нее va_arg
. Таким образом, после его возвращения вам больше не разрешается использовать varg
. Вы должны вызвать va_end
прежде чем делать что-либо еще с этим. Вместо этого вы используете его в следующей итерации цикла без первого вызова va_end
. Таким образом, вы сталкиваетесь с неопределенным поведением.
va_copy
можно использовать, если вы хотите обработать список дважды. Хотя то, что пытается OP, вероятно, невозможно сделать переносимо.