vprintf не использует элемент из va_list

0

Я пытаюсь написать вариант 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);
}

Кажется, что эта работа выполнена.

  • 1
    Я бы не рассчитывал, что это будет работать во всех системах, поскольку тип, предоставленный va_arg, должен быть фактическим типом аргумента. Цитируя стандарт: «Если нет фактического следующего аргумента или если тип не совместим с типом фактического следующего аргумента (как продвигается в соответствии с продвижением аргумента по умолчанию), поведение не определено». Предусмотрено два исключения: void * и char * взаимозаменяемы; и неподписанные и подписанные типы являются взаимозаменяемыми, если значение положительное.
Теги:
variadic-functions
printf

2 ответа

1
Лучший ответ

Va_list - это не что иное, как адрес (в типичных реализациях). Он передается по значению функции, поэтому оригинал в вызывающей функции не модифицируется.

  • 0
    Понимаю. Так что мое предположение было неверным.
1

То, что вы здесь делаете, - это неопределенное поведение. В стандарте 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. Таким образом, вы сталкиваетесь с неопределенным поведением.

  • 0
    В дополнение к этому; va_copy можно использовать, если вы хотите обработать список дважды. Хотя то, что пытается OP, вероятно, невозможно сделать переносимо.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню