Передача аргументов переменной в другую функцию, которая принимает список аргументов переменной - PullRequest
90 голосов
/ 20 августа 2010

Итак, у меня есть 2 функции, которые обе имеют одинаковые аргументы

void example(int a, int b, ...);
void exampleB(int b, ...);

Теперь example вызывает exampleB, но как мне передать переменные в списке аргументов переменных без изменения exampleB (поскольку это уже используется и в других местах).

Ответы [ 8 ]

105 голосов
/ 20 августа 2010

Вы не можете сделать это напрямую; Вы должны создать функцию, которая принимает va_list:

#include <stdarg.h>

static void exampleV(int b, va_list args);

void example(int a, int b, ...)
{
    va_list args;
    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...
}
21 голосов
/ 16 сентября 2017

Возможно, здесь можно бросить камень в пруд, но, похоже, он работает довольно хорошо с C ++ 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++.

15 голосов
/ 20 августа 2010

вы должны создать версии этих функций, которые принимают va_list и передают их.Посмотрите на vprintf в качестве примера:

int vprintf ( const char * format, va_list arg );
4 голосов
/ 07 января 2014

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

2 голосов
/ 20 августа 2010

Между прочим, многие реализации на C имеют внутреннюю вариацию v? Printf, которая IMHO должна была быть частью стандарта C.Точные детали меняются, но типичная реализация примет структуру, содержащую указатель на функцию символьного вывода и информацию о том, что должно произойти.Это позволяет printf, sprintf и fprintf использовать один и тот же механизм 'core'.Например, 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 (и какой бы механизм настройки она не использовала), можно расширить ее всеми возможными вариантами.

0 голосов
/ 22 апреля 2019

Возможный способ - использовать #define:

#define exampleB(int b, ...)  example(0, b, __VA_ARGS__)
0 голосов
/ 20 августа 2010

Исходя из комментария, который вы добавляете vsprintf, и что он помечен как C ++, я бы посоветовал не пытаться сделать это, а изменить интерфейс, чтобы использовать вместо него C ++ iostream.Они имеют преимущества перед линейкой функций print, такие как безопасность типов и возможность печати элементов, с которыми printf не сможет справиться.Некоторая переделка сейчас может спасти значительное количество боли в будущем.

0 голосов
/ 20 августа 2010

Используя новый стандарт C ++ 0x, вы можете сделать это с помощью шаблонов с переменным числом аргументов или даже преобразовать этот старый код в синтаксис нового шаблона, не нарушая ничего.

...