天天看点

C/C++ asprintf正确使用方法,以及和sprintf的比较

最近公司开发的code defect工具,扫出很多asprintf的问题,下面是sample code

int testAsprintf(int num) {
    char *testStr = NULL;
    asprintf(&testStr, "%d", num);
    
    // use testStr doing something
    
    if (testStr != NULL) {
        free(testStr);
        testStr = NULL;
    }
    return 1;
}
           

看过code之后,想到的应该是testStr在asprintf之后没有判断是否是NULL,所以马上改了一版。

int testAsprintf(int num) {
    char *testStr = NULL;
    asprintf(&testStr, "%d", num);
    if(testStr == NULL) {
        return 0;
    }
    
    // use testStr doing something
    
    if (testStr != NULL) {
        free(testStr);
        testStr = NULL;
    }
    return 1;
}
           

自认为上面的code没有问题了,asprintf函数经常用,知道需要free,在加上判断条件简直是完美的sample。今日有些时间在网上看了一下asprintf的原型和解释:

**#include <stdio.h>

int asprintf(char **strp, const char *fmt, …);

int vasprintf(char *strp, const char fmt, va_list ap);

Description

The functions asprintf() and vasprintf() are analogs of sprintf() and vsprintf(), except that they allocate a string large enough to hold the output including the terminating null byte, and return a pointer to it via the first argument. This pointer should be passed to free() to release the allocated storage when it is no longer needed.

Return Value

When successful, these functions return the number of bytes printed, just like sprintf(). If memory allocation wasn’t possible, or some other error occurs, these functions will return -1, and the contents of strp is undefined.

我在这里简单解释一下:asprintf()类似于sprintf(),它会分配一个足够大的空间来保存输出,包括终止字节,通过第一个参数返回一个指针,如果指针不再有用,需要进行free。如果函数成功运行,函数的返回值是字节的个数,如果memory分配失败或者有其他error发生,函数会返回-1,第一个参数strp的值是未定义的。

从说明上看,这个函数是有返回值,如果函数失败了,那么函数返回-1,而第一个参数strp的结果是没有定义的(undefined),所以判断函数是否成功,需要使用函数返回值,而不应该使用第一个参数strp进行判断。上面的例子应该写成如下:

int testAsprintf(int num) {
    char *testStr = NULL;
    if(asprintf(&testStr, "%d", num) < 0) {
        return 0;
    }
    
    // use testStr doing something
    
    if (testStr != NULL) {
        free(testStr);
        testStr = NULL;
    }
    return 1;
}
           

asprintf相对sprintf来说更安全,asprintf是动态分配memory的,不会出现memory overflow的情况,当然它的缺点是使用后需要free。上面的例子如果使用是sprintf()就是下面的样子:

int testAsprintf(int num) {
    char testStr[10] = {0}; // memory是提前分配好的,数组的长度一般都会比较大,但是后面也不需要进行free了。
    if (sprintf(testStr, "%d", num) < 0) { //一定要确定空间分配的足够大,能够完全容下output。
        return 0
    }
    
    // use testStr doing something
    
    return 1;
}
           

最近总是感觉一些基本知识没有那么牢,code写得有些丑陋,看别人code怎么写的,自己就照搬。虽然写了很长时间的code,自我感觉都是非常熟练,没有问题了,但是还是差那么一点。这一点应该就是和大牛的区别了,自己总是半瓶子晃荡,感觉自己满了。