2010-08-20 2 views
71

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

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

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

+5

Возможный дубликат [Переслать вызов вариационной функции в C] (http://stackoverflow.com/questions/150543/forward-an-invocation-of-a-variadic-function-in-c) –

+0

Ну на этом решении было использовано vprintf, и здесь это не так. –

ответ

79

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

Предполагалось, что я должен был сделать что-то вроде этого, проблема в том, что функция-пример в основном представляет собой оболочку для vsprintf и не намного больше:/ –

+0

@Xeross: Обратите внимание, что это не изменяет внешнюю спецификацию того, что пример B делает - он просто меняет внутреннюю реализация. Я не уверен, в чем проблема. –

+1

Я обработал его аналогично этому, спасибо. –

14

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

int vprintf (const char * format, va_list arg); 
-1

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

+0

, к сожалению, это невозможно во всех случаях - просто попробуйте использовать lambdas – serup

0

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

+0

К каким преимуществам вы относитесь? – cjcurrie

+0

@cjcurrie: преимущество - это безопасность типа, даже с пользовательскими типами. Конечно, функции C не могут обрабатывать пользовательские типы. –

2

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

1

Я также хотел, чтобы обернуть Printf и нашел полезный ответ здесь:

How to pass variable number of arguments to printf/sprintf

Я не был заинтересован в производительности (я уверен, что этот кусок кода может быть улучшена в ряде способы, не стесняйтесь сделать это :)), это для общего debugprinting только поэтому я сделал это:

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

4

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

Смежные вопросы