it-swarm.com.ru

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

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

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

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

89
Not Available

Вы не можете сделать это напрямую; Вы должны создать функцию, которая принимает 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...
}
105
Jonathan Leffler

Может быть, бросить камень в пруд здесь, но, кажется, работает довольно хорошо с C++ 11 variadic шаблонов:

#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++.

20
Vincent Fourmond

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

int vprintf ( const char * format, va_list arg );
15
tenfour

Я также хотел обернуть 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 << " )";

В некоторых аспектах выходы c ++ прекрасны, но практически становятся ужасающими, если вы хотите напечатать что-то подобное с небольшими строками, такими как скобки, двоеточия и запятые, вставленные между числами.

4
Axel

Кстати, у многих реализаций 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 (и какой бы механизм ее настройки не использовался), можно расширить ее всеми видами вариаций.

2
supercat

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

#define exampleB(int b, ...)  example(0, b, __VA_ARGS__)
0
Shai

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

0
Mark B