Подтвердить что ты не робот

Пропустить va_list или указатель на va_list?

Предположим, что у меня есть функция, которая принимает переменные аргументы (...) или va_list, переданные из другой такой функции. Основная логика заключается в самой этой функции (пусть ее называют f1), но я хочу, чтобы она передавала va_list в другую функцию (пусть она называет ее f2), которая будет определять следующий тип аргумента, получить ее, используя va_arg и правильно конвертировать и сохранять его для использования вызывающим абонентом.

Достаточно ли передать va_list в f2, или необходимо передать указатель на va_list. Если va_list не требуется, чтобы быть типом массива или хранить данные о местоположении в месте, на которое указывает объект va_list (а не сам объект), я не вижу, как передача его по значению может разрешить вызывающую функцию (f1), чтобы "видеть" изменения вызываемой функции, сделанные с помощью va_arg.

Может ли кто-нибудь пролить свет на это? Меня интересует то, что требует стандарт, а не то, что позволяет определенная реализация.

4b9b3361

Ответ 1

Похоже, вам нужно будет передать указатель на va_list. Для получения дополнительной информации см. Раздел

Ответ 2

В моем понимании вы должны передать va_list напрямую (а не указатель на него). Кажется, это поддерживается comp.lang.c:

"Va_list сам по себе не является списком переменных аргументов, он действительно является указателем на один. То есть, функция, которая принимает va_list, сама по себе не является varargs, и наоборот".

Ответ 3

Я нахожу тексты весьма двусмысленными по этому вопросу. Простейшим может быть, пожалуй, посмотреть в стандарте, как предполагается, что его предопределенные функции с va_list должны принимать его, например vsnprintf. И это явно по стоимости, а не по ссылке.

Ответ 4

Функции в стандартной библиотеке C пропускают va_list сам элемент (man 3 vprintf):

   #include <stdarg.h>

   int vprintf(const char *format, va_list ap);
   int vfprintf(FILE *stream, const char *format, va_list ap);
   int vsprintf(char *str, const char *format, va_list ap);
   int vsnprintf(char *str, size_t size, const char *format, va_list ap);

Ответ 5

Передача указателя на va_list отлично работает в 32-битной системе. Вы даже можете выбрать один параметр в подпрограмме. Но, похоже, он не работает в 64-битной системе, будет генерировать ошибку сегмента в va_arg().

Ответ 6

Вы должны передать указатель на va_list, если вы хотите использовать его в подфункции, а затем не нужно сразу передавать его в va_end. От C99:

Разрешается создать указатель на va_list и передать этот указатель другой функции, и в этом случае исходная функция может дополнительно использовать исходный список после возврата другой функции.

Стандарт позволяет это, однако, на некоторых 64-битных платформах, где va_list является типом массива, это не работает. Поскольку адрес массива совпадает с адресом первого элемента массива, передача указателя на va_list приведет к ошибке при вызове va_arg с указателем на va_list в качестве аргумента.

Чтобы обойти это, можно получить va_list в качестве нетрадиционного имени аргумента (обычно с одним или несколькими подчеркиваниями), а затем создать новый локальный va_list, например, так:

#include <stdarg.h>

int vfoo(va_list ap_)
{
    int ret;
    va_list ap;
    va_copy(ap, ap_);
    ret = vbar(&ap);
    /* do other stuff with ap */
    va_end(ap);
    return ret;
}

Это подход, который я использую в своей реализации vsnprintf для вызова других функций из него для форматирования.