#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. Как это неверно? Я с готовностью признаю, что она неполная, поскольку теперь я вижу, что на самом деле было много проблем с кодом, но если я сказал что-то действительно неправильное, я хотел бы знать, что.