2010-03-10 3 views
6

Допустим, я хочу сделать что-то вроде этогоC, Работа с переменными функциями аргумента

void my_printf(char *fmt,...) { 
char buf[big enough]; 
sprintf(buf,fmt,...); 
} 

Что такое правильный способ передачи переменного числа аргументов непосредственно к функции с переменной принимает аргументы?

+0

Как вы узнаете, что буфер достаточно большой? И вы действительно должны вернуть количество конверсий, выполняемых sprintf(), иначе пользователи не смогут узнать, какая функция работала. – 2010-03-10 22:23:20

+0

Я разделил все, что не было существенным для иллюстрации моей точки. Очевидно, что в моем коде выпуска я более подробно :) – Mike

ответ

9

sprintf имеет форму va_list под названием vsprintf. Передайте va_list, который вы строите локально в качестве последнего аргумента.

void my_printf(char *fmt,...) { 
va_list ap; 
va_start(ap, fmt); 

char buf[big enough]; 
vsprintf(buf,fmt,ap); 

va_end(ap); 
} 
+3

Оперативный заголовок ''. –

+0

Если это доступно, вы должны использовать 'vsnprintf'. –

1

Я не уверен, насколько полезным этот код будет, как это C++, но он показывает, как проверить, используя Win32 специфическую функцию vsnprintf(), что буфер выделяется достаточно большой, и если не выделяет большую. И он возвращает std :: string, поэтому вам придется использовать malloc/realloc, чтобы справиться с этим. Но какого черта:

string Format(const char * fmt, ...) { 
    const int BUFSIZE = 1024; 
    int size = BUFSIZE, rv = -1; 
    vector <char> buf(size); 
    do { 
     va_list valist; 
     va_start(valist, fmt); 
     // if vsnprintf() returns < 0, the buffer wasn't big enough 
     // so increase buffer size and try again 
     rv = _vsnprintf(&buf[0], size, fmt, valist); 
     va_end(valist); 
     size *= 2; 
     buf.resize(size); 
    } 
    while(rv < 0); 
    return string(&buf[0]); 
} 
-1

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

va_list ap; 
char *param; 
va_start(ap,fmt); 
param = va_arg(ap,char*); 
while(param) 
{ 
do something... 
param = va_arg(ap,char*); 
} 

или вы можете иметь несколько параметров, как первые пары вашей функции

void my_printf(int param_num,...) 
{ 
va_list ap; 
char *param; 
va_start(ap,fmt); 
while(param_num) 
{ 
do something... 
param = va_arg(ap,char*); 
param_num--; 
} 

} 

его действительно до вас, возможности безграничны. Я думаю, что единственным реальным требованием к эллипсам является то, что он имеет по крайней мере один параметр перед эллипсами.

+0

, требующее, чтобы пользователь указывал количество параметров, было бы катастрофой дизайна – Mike

+1

, моя точка зрения - это не голубь, забитый в определенное использование. Пользователь функции может решить, что лучше для их ситуации. Передача числа параметров не отличается от числа, вложенного в строку ... т.е. sprintf («% d% d», a, b) является таким же, как yourprintf (2, a, b), sprintf так же, как подвержен ошибкам пользователя. – Medran

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