Скажем, у меня есть функция C, которая принимает переменное число аргументов: как я могу вызвать другую функцию, которая ожидает от нее переменное количество аргументов, передавая все аргументы, полученные в первую функцию?
Пример:
void format_string(char *fmt, ...);
void debug_print(int dbg_lvl, char *fmt, ...) {
format_string(fmt, /* how do I pass all the arguments from '...'? */);
fprintf(stdout, fmt);
}
c
variadic-functions
Висент Марти
источник
источник
Ответы:
Чтобы передать эллипсы, вы должны преобразовать их в va_list и использовать этот va_list во второй функции. В частности,
источник
format_string
то вряд ли это будет полезно, так как придется вносить изменения на месте в fmt, что, конечно же, не следует делать. Опции могут включать полное избавление от format_string и использование vfprintf, но это делает предположения о том, что фактически делает format_string, или если format_string возвращает другую строку. Я отредактирую ответ, чтобы показать последнее.argptr
и вызываемая функцияargptr
вообще использует функцию , единственное, что можно сделать безопасно, это вызватьva_end()
и затем перезапуститьva_start(argptr, fmt);
для повторной инициализации. Или вы можете использовать,va_copy()
если ваша система поддерживает это (C99 и C11 требуют этого; C89 / 90 этого не сделали).Невозможно вызвать (например) printf, не зная, сколько аргументов вы ему передаете, если только вы не захотите использовать непослушные и непереносимые уловки.
Обычно используют раствор , чтобы всегда обеспечивать альтернативную форму функций vararg, так что
printf
имеет ,vprintf
который принимаетva_list
на месте...
. В...
версии просто обертки вокругva_list
версий.источник
vsyslog
это не POSIX- совместимый.Функции Variadic могут быть опасными . Вот более безопасный трюк:
источник
#define callVardicMethodSafely(values...) ({ values *v = { values }; _actualFunction(values, sizeof(v) / sizeof(*v)); })
В великолепном C ++ 0x вы можете использовать различные шаблоны:
источник
Вы можете использовать встроенную сборку для вызова функции. (в этом коде я предполагаю, что аргументы являются символами).
источник
Вы можете попробовать макрос также.
источник
Хотя вы можете решить передать средство форматирования, предварительно сохранив его в локальном буфере, но это требует стека и может когда-нибудь стать проблемой. Я попытался следовать, и, кажется, работает нормально.
Надеюсь это поможет.
источник
Решение Росса немного подчищено. Работает только если все аргументы являются указателями. Также языковая реализация должна поддерживать удаление предыдущей запятой, если
__VA_ARGS__
она пуста (как в Visual Studio C ++, так и в GCC).источник
Допустим, у вас есть типичная переменная функция, которую вы написали. Поскольку по крайней мере один аргумент необходим перед переменным
...
, вы всегда должны писать дополнительный аргумент при использовании.Или ты?
Если вы оберните свою переменную функцию в макрос, вам не понадобится предшествующий аргумент. Рассмотрим этот пример:
Это, очевидно, намного удобнее, поскольку вам не нужно каждый раз указывать начальный аргумент.
источник
Я не уверен, что это работает для всех компиляторов, но до сих пор это работало для меня.
Вы можете добавить ... к inner_func (), если хотите, но вам это не нужно. Это работает, потому что va_start использует адрес данной переменной в качестве начальной точки. В этом случае мы даем ему ссылку на переменную в func (). Таким образом, он использует этот адрес и читает переменные в стеке. Функция inner_func () читает адрес стека func (). Так что это работает, только если обе функции используют один и тот же сегмент стека.
Макросы va_start и va_arg, как правило, будут работать, если вы дадите им любую переменную в качестве отправной точки. Поэтому, если вы хотите, вы можете передавать указатели на другие функции и использовать их тоже. Вы можете сделать свои собственные макросы достаточно легко. Все макросы - это адреса типов памяти. Однако заставить их работать для всех компиляторов и соглашений о вызовах раздражает. Так что обычно проще использовать те, которые поставляются с компилятором.
источник