2011-10-14 102 views
1

1)为什么在/* test1 */块下的代码不会打印出任何东西,但/* test2 */下的代码打印是否正确?C中的可变参数函数

2)如何在/* test 1 */代码块中使用va_arg(va, char*)


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 memory\n"); /* 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 %s\n", pinfile); 

    return 0; 
} 

回答

6

/* test 1 */下的代码不会打印任何内容,因为vsnprint()函数不打印到标准输出;它只是将其输出写入提供的缓冲区。

这纯粹是运气,如果代码没有崩溃,但是,因为该行:

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

实际上告诉calloc()分配0字节的内存。因此,我不认为内存logbuf指向0也是如此 - 因此,不仅缓冲区零字节长,而且调用strlen()可能会导致崩溃或给出无效结果。

此外,vsnprint()的第二个参数应该是缓冲区的大小,即您为logbuf分配的大小,而不是已经在其中的任何字符串的长度;它将限制写入缓冲区的字节数以避免缓冲区溢出。

所以得到的一切工作,你需要改变:

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

..to ..

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

..to为LOGBUFFERSIZE字节1项分配空间。并且还改变:

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

..to ..

vsnprintf(logbuf, LOGBUFFERSIZE, fmt, va); 

..to通过它你的缓冲区的大小和删除无用(void)演员。并且还添加一行打印logbuf,如:

fputs(logbuf, stderr); 

之后它。

+0

谢谢。我显然误解了calloc和vsnprintf的正确用法。 – twfx

4

此:

vsnprintf(logbuf, strlen(logbuf)... 

永远不会格式化任何东西,因为logbuf全部为零(已经由calloc分配的,所以strlen将返回零,这使得vsnprintf从来没有格式化任何东西,因为你告诉它打印最多零个字符

+4

即使在解决该问题之后,仍然不会打印任何内容,因为'vsnprintf'不会打印。它将结果放入'logbuf'中,但绝不会打印'logbuf'。 –

+1

你疯了吗?将其更改为malloc不是解决方案 - 现在您正在使用未初始化的内存。你需要传递LOGBUFFERSIZE作为第二个参数而不是strlen(logbuf)。 –

+1

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); – twfx