Bezdepbonusu7Программирование: статьи и ответы

Вопрос

C, Работа с функциями с переменным аргументом

Автор вопроса: MikeОтветов: 3

Допустим, я хочу сделать что-то вроде этого

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

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

  • Как вы узнаете, что буфер достаточно велик? И вы действительно должны вернуть количество преобразований, выполненных sprintf(), иначе пользователи не смогут узнать, что функция сработала. 11.03.2010
  • Я вырезал все, что не было необходимо для иллюстрации моей точки зрения. Очевидно, в моем коде релиза я гораздо тщательнее :) Mike 11.03.2010

cvariablesarguments

Ответы

Ответ 1 · рейтинг 9 · Johannes Schaub - litb

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);
}

Ответ 2 · рейтинг 1 · Community

Я не уверен, насколько полезным будет этот код, поскольку он написан на 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] );
}

Ответ 3 · рейтинг -1 · Medran

Вы можете использовать функции стиля 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--;
}

}

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы