天天看點

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,自我感覺都是非常熟練,沒有問題了,但是還是差那麼一點。這一點應該就是和大牛的差別了,自己總是半瓶子晃蕩,感覺自己滿了。