переменная функция в C

#c #variadic-functions

#c #вариативные функции

Вопрос:

1) Почему код под /* test1 */ чанком ничего не выводит, но код при /* test2 */ печати корректен?

2) Как использовать va_arg(va, char*) в /* test 1 */ фрагменте кода.


 void rdfDBG(int dbglevel, const char *fmt, ...) {

    va_list va;

#if 1 /* test 1 */
    char* logbuf;

    if ((logbuf = calloc(0x0, LOGBUFFERSIZE))== NULL)
        fprintf(stderr, "out of memoryn"); /* 1. Is there a better way instead of using fprintf? */

    va_start(va, fmt);
    (void) vsnprintf(logbuf, strlen(logbuf), fmt, va); /* 2. print nothing */
    va_end(va);

    free(logbuf);
#endif

#if 0 /* test 2 */
    va_start(va, fmt);
    vprintf(fmt, va); /* 2. print "pinfile pings6.txt" */
    va_end(va);
#endif


}


int ptInitialize(){

    char* pinfile;
    pinfile = "pings6.txt";

    rdfDBG(kINFO, "pinfile %sn", pinfile);

    return 0;
}
  

Ответ №1:

Приведенный ниже код /* test 1 */ ничего не печатает, потому vsnprint() что функция не печатает в стандартный вывод; он просто записывает свои выходные данные в предоставленный буфер.

Это чистая удача, если код не сработал, хотя, потому что строка:

 if ((logbuf = calloc(0x0, LOGBUFFERSIZE))== NULL)
  

на самом деле указывает calloc() выделить 0 байт памяти. Из-за этого я не думаю, что гарантируется, что точки памяти logbuf также обнулены — так что длина вашего буфера не только равна нулю байтов, но и вызов strlen() его может привести к сбою или дать неверный результат.

Кроме того, вторым аргументом to vsnprint() должен быть размер буфера, то есть размер, для которого вы выделили logbuf , а не длина какой-либо строки, уже находящейся в нем; это ограничение количества байтов, записываемых в буфер, чтобы избежать переполнения буфера.

Итак, чтобы все заработало, вам нужно изменить:

     if ((logbuf = calloc(0x0, LOGBUFFERSIZE))== NULL)
  

..кому..

     if ((logbuf = calloc(1, LOGBUFFERSIZE))== NULL)
  

..чтобы выделить место для 1 элемента LOGBUFFERSIZE байтов. А также изменить:

 (void) vsnprintf(logbuf, strlen(logbuf), fmt, va);
  

..кому..

 vsnprintf(logbuf, LOGBUFFERSIZE, fmt, va);
  

.. чтобы передать ей размер вашего буфера и удалить бесполезное (void) приведение. А также добавьте строку для печати logbuf , например:

 fputs(logbuf, stderr);
  

после нее.

Комментарии:

1. Спасибо. Я, по-видимому, неправильно понял правильное использование calloc и vsnprintf .

Ответ №2:

Это:

 vsnprintf(logbuf, strlen(logbuf)...
  

Никогда ничего не будет форматировать, потому logbuf что все нули (были выделены calloc , и поэтому strlen вернут ноль, из-за чего vsnprintf никогда ничего не форматирует, потому что вы сказали ему печатать не более нулевых символов.

Комментарии:

1. Даже после устранения этой проблемы вы все равно ничего не напечатаете, потому vsnprintf что не печатается. Она помещает результат в logbuf , но вы никогда не печатаете logbuf .

2. Ты что, с ума сошел? Изменение ее на malloc не было решением — теперь вы используете неинициализированную память. Вам нужно передать LOGBUFFERSIZE в качестве второго аргумента, а не strlen(logbuf).

3. if ((logbuf = malloc(LOGBUFFERSIZE))== NULL) fprintf(stderr, «не хватает памяти n»); va_start(va, fmt); (void) vsnprintf(logbuf, LOGBUFFERSIZE, fmt, va); fprintf(stderr, «%s», logbuf);va_end(va);

4. Три голоса против? Действительно? Этот ответ явно неверен. Ответ Дмитрия правильный.

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