2010-12-02 3 views
21

Можно создать дубликат:
C/C++: Passing variable number of arguments aroundКак использовать __VA_ARGS__ внутри функции C вместо макроса?

настоящее время я использую следующий макрос объявлен в моем файле C.

#define COMMON_Print(...) printf (__VA_ARGS__) 

Теперь, когда вызов работает нормально, но получается, что мне нужно, чтобы быть в состоянии создать функцию C, которая выглядит примерно так:

void COMMON_Print(...) 
{  
    printf (__VA_ARGS__); 
} 

Так что функция не работает, я получить ошибку

"ошибка: неопределенный идентификатор __VA_ARGS__"

Сложность моего проекта требует наличия функции, так как это интерфейс ... Итак, как я могу получить параметры ... и передать их функции printf? Или лучше, что я делаю неправильно?

Спасибо!

+1

Посмотреть этот http://stackoverflow.com/questions/205529/cc-passing-variable-number-of-arguments -around – Kos 2010-12-02 20:19:53

ответ

36

Каждая из функций ?printf имеет соответствующую функцию v?printf, которая делает то же самое, но принимает список переменных аргументов va_list.

#include <stdio.h> 
#include <stdarg.h> 

void COMMON_Print(char *format, ...) 
{ 
    va_list args; 

    va_start(args, format); 
    vprintf(format, args); 
    va_end(args); 
} 

Side Примечание: Обратите внимание, чтоva_start принимает имя последнего аргумента перед ... в качестве параметра. va_start - это макрос, который делает некоторую магию на основе стека для извлечения аргументов переменной и для этого нужен адрес последнего фиксированного аргумента.

В результате этого должен быть хотя бы один фиксированный аргумент, поэтому вы можете передать его va_start. Вот почему я добавил аргумент format вместо того, чтобы придерживаться более простой декларации COMMON_Print(...).

См:http://www.cplusplus.com/reference/clibrary/cstdio/vprintf/

+0

Если вы используете макросы, вам не нужен предшествующий arg. Рассмотрим этот пример: `#define LOGI (...) ((void) __ android_log_print (ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS __))` Это, очевидно, очень удобно с точки зрения использования. – 2015-07-28 11:39:11

15

__VA_ARGS__ только для макросов; вариационные функции довольно разные. Вы должны использовать va_start, va_arg и va_end от stdarg.h для их обработки.

Во-первых, ваша функция должна по крайней мере один именованный параметр, например:

void COMMON_Print(const char* fmt, ...) 

Затем вы можете определить va_list и использовать va_start, чтобы установить его:

va_list args; 
va_start(args, fmt); 
// your code here 
va_end(args); 

Теперь вы можете использовать args для доступ к аргументам; вызов va_arg(args, TYPE) вернет следующий вариационный аргумент, поэтому вы можете просто продолжать называть это, пока не прочитаете все аргументы.

Если вы просто пытаетесь вызвать printf, есть вариант Printf называется vprintf, который принимает va_list непосредственно:

vprintf(fmt, args); 

Там нет простого способа вызвать одну VARIADIC функции от другого; вам нужно что-то наподобие vprintf, который принимает все va_list

+0

Спасибо за ваше объяснение. Спасибо за помощь и объяснения, которые они действительно помогли! :) – Jona 2010-12-02 20:33:33

+0

'va_arg (args, TYPE)' возвращает NULL, только если NULL был передан вызывающим. Для va_arg нет конечного условия по умолчанию. Вы должны либо передать контрольное значение, либо узнать точное количество параметров, переданных параметром, либо подсчитав количество% в строке формата printf. – 2010-12-02 21:05:43

4

__VA_ARGS__ предназначено только для макросов.

Цепочное число аргументов другой функции не может быть выполнено напрямую. Вместо этого вы должны передать va_list, а функция, которую вы вызываете, должна взять va_list. К счастью, есть вариация Printf, что делает это, ваша функция должна быть написана так:

void COMMON_Print(char *format,...) 
{  
    va_list args; 
    va_begin(args,format); 
    vsprintf(format,args); 
    va_end(args); 
} 
Смежные вопросы