Передача переменных в другую функцию, которая принимает список переменных аргументов

Итак, у меня есть 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, вы можете сделать это с помощью вариативных шаблонов или даже преобразовать этот старый код в новый синтаксис шаблона, не нарушая ничего.