Передача переменных в другую функцию, которая принимает список переменных аргументов
Итак, у меня есть 2 функции, которые имеют одинаковые аргументы
void example(int a, int b, ...);
void exampleB(int b, ...);
Теперь example
вызывает exampleB
, но как я могу передавать по переменным в списке аргументов переменных без изменения exampleB
(так как это уже используется в другом месте).
Ответы
Ответ 1
Вы не можете сделать это напрямую; Вы должны создать функцию, которая принимает va_list
:
#include <stdarg.h>
static void exampleV(int b, va_list args);
void exampleA(int a, int b, ...) // Renamed for consistency
{
va_list args;
do_something(a); // Use argument a somehow
va_start(args, b);
exampleV(b, args);
va_end(args);
}
void exampleB(int b, ...)
{
va_list args;
va_start(args, b);
exampleV(b, args);
va_end(args);
}
static void exampleV(int b, va_list args)
{
...whatever you planned to have exampleB do...
...except it calls neither va_start nor va_end...
}
Ответ 2
Может быть, в этом месте плыть скала в пруду, но, похоже, он работает с С++ 11 вариационными шаблонами:
#include <stdio.h>
template<typename... Args> void test(const char * f, Args... args) {
printf(f, args...);
}
int main()
{
int a = 2;
test("%s\n", "test");
test("%s %d %d %p\n", "second test", 2, a, &a);
}
По крайней мере, он работает с g++
.
Ответ 3
вам следует создать версии этих функций, которые принимают va_list и передают их. Посмотрите vprintf
в качестве примера:
int vprintf ( const char * format, va_list arg );
Ответ 4
Я также хотел обернуть printf и нашел полезный ответ здесь:
Как передать переменное количество аргументов printf/sprintf
Меня совсем не интересовала производительность (я уверен, что этот фрагмент кода можно улучшить несколькими способами, не стесняйтесь делать это:)), это для общей отладки, только так я сделал это:
//Helper function
std::string osprintf(const char *fmt, ...)
{
va_list args;
char buf[1000];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args );
va_end(args);
return buf;
}
который я тогда могу использовать так:
Point2d p;
cout << osprintf("Point2d: (%3i, %3i)", p.x, p.y);
instead of for example:
cout << "Point2d: ( " << setw(3) << p.x << ", " << p.y << " )";
С++ ostreams прекрасны в некоторых аспектах, но практически становятся ужасающими, если вы хотите напечатать что-то вроде этого несколькими строками, такими как скобки, двоеточия и запятые, вставленные между цифрами.
Ответ 5
Кстати, во многих реализациях C есть внутренняя вариация v? printf, которая должна была быть IMHO частью стандарта C. Точные данные различаются, но типичная реализация будет принимать структуру, содержащую указатель функции символа-вывода, и информацию о том, что должно произойти. Это позволяет printf, sprintf и fprintf использовать один и тот же "основной" механизм. Например, vsprintf может выглядеть примерно так:
void s_out(PRINTF_INFO *p_inf, char ch)
{
(*(p_inf->destptr)++) = ch;
p_inf->result++;
}
int vsprintf(char *dest, const char *fmt, va_list args)
{
PRINTF_INFO p_inf;
p_inf.destptr = dest;
p_inf.result = 0;
p_inf.func = s_out;
core_printf(&p_inf,fmt,args);
}
Затем функция core_printf вызывает p_inf- > func для каждого символа, который будет выводиться; функция вывода может затем отправить символы на консоль, файл, строку или что-то еще. Если одна реализация предоставляет функцию core_printf (и какой бы механизм установки она не использовала), она может распространяться на всевозможные варианты.
Ответ 6
На основе комментария, который вы обмениваете vsprintf
, и что это помечено как С++, я бы предложил не пытаться это сделать, но вместо этого измените свой интерфейс, чтобы использовать С++ iostreams. Они имеют преимущества перед линейкой функций print
, такими как безопасность типов и возможность печатать элементы, которые printf
не сможет обрабатывать. Некоторая переделка теперь может сэкономить значительную боль в будущем.
Ответ 7
Возможный способ - использовать #define:
#define exampleB(int b, ...) example(0, b, __VA_ARGS__)
Ответ 8
Используя новый стандарт С++ 0x, вы можете сделать это с помощью вариативных шаблонов или даже преобразовать этот старый код в новый синтаксис шаблона, не нарушая ничего.