Переменные списки аргументов в C ++ - PullRequest
0 голосов
/ 16 апреля 2011

У меня есть этот метод (с использованием кода из справочной страницы vsnprintf):

MYSQL_RES *nsDatabase::queryf(const char *fmt,...){
  int n, size = 1024;
  char *query=NULL,*np;
  va_list ap;

  if (this->dbLink == NULL){
    return NULL;
  }

  query = (char *) malloc (size);
  if (query == NULL) return NULL;//memory error

  while (1) {
    va_start(ap, fmt);
    n=vsnprintf(query,size,fmt,ap);
    va_end(ap);
    if (n > -1 && n < size){// format string succeeded
      break;
    }
    if (n > -1)    /* glibc 2.1 */
       size = n+1; /* precisely what is needed */
    else           /* glibc 2.0 */
       size *= 2;  /* twice the old size */

    np = (char *) realloc (query, size);
    if (np == NULL) {
       printf("memory error\n");
       FREE(query);
       return NULL;//again memory error
    } else {
       query = np;
    }
  }

  MYSQL_RES *r = this->query(query);

  FREE(query);

  if(r == NULL){
    return NULL; //mysql error
  }

  return mysql_store_result(this->dbLink);
}

Я хочу сделать общую функцию queryFormat, которая будет вычислять размер, необходимый для форматированной строки, выделять память, формат печатив нем и вернуть строку (не реальный код, псевдокод ):

char *queryFormat(const char *fmt, va_list ap){
  // allocate memory
  // problem - can I use vsnprintf multiple times here (to determine the size of formatted string and allocate memory)
  return <formatted string>;
}

Затем мне нужно вызвать его из всех функций, которые форматируют запросы (не реальный код):

queryRow(const char *fmt,...){
  va_start(ap, fmt);
  // I need to call vsnprintf many times in queryFormat ... Do I need to call va_start() before every call to fsnprintf ?
  char * formattedQuery = queryFormat(query, size, fmt, ap);
  va_end(ap);
  MYSQL_RES *r = this->query(formattedQuery);
  free(formattedQuery);

  ...

}

Я пишу для GCC под Linux, но код должен работать под MinGW и CygWin.

Ответы [ 2 ]

0 голосов
/ 16 марта 2012

Я считаю, что это должно помочь любому, кто погуглил здесь, в поисках решения проблемы того, как «повторно» использовать va_list в функции, в которой он уже был передан в качестве параметра:

// Incorrect:
/*void g(int foo, va_list ap) {
    vprintf("%s %s %s\n", ap);
    vprintf("%s %s %s\n", ap);
}*/

void g(int foo, va_list ap) {
    va_list copy;
    va_copy(copy, ap);
    vprintf("%s %s %s\n", copy);
    va_copy(copy, ap);
    vprintf("%s %s %s\n", copy);
}

void f(int foo, ...) {
    va_list ap;
    va_start(ap, foo);
    g(foo, ap);
    va_end(ap);
}

int main() {
    f(42, "aaa", "bbb", "ccc");
    return 0;
}
0 голосов
/ 16 апреля 2011

Смотрите это - http://publications.gbdirect.co.uk/c_book/chapter9/stdarg.html.There - хороший пример в книге Кернигана и Ричи.

РЕДАКТИРОВАТЬ То же самое и в C ++.Вы можете посмотреть на это тоже.- http://www.cplusplus.com/reference/clibrary/cstdarg/va_start/

РЕДАКТИРОВАТЬ 2 http://www.cplusplus.com/reference/clibrary/cstdio/vprintf/. Я думаю, что это поможет вам.

...