天天看點

了解snprintf()函數

了解snprintf()函數

在程式設計中,需要關注snprintf()的兩個問題:一是它的傳回值,二是它的第二個參數。

看看下面這段代碼的運作結果:

#include 

int main()

{

        int ret;

        char str[10];

        printf("sizeof(str) = %d\n", sizeof(str));

        ret = snprintf(str, sizeof(str), "%s", "abc");

        printf("%d:%s => %d\n",strlen(str), str, ret);

        ret = snprintf(str, sizeof(str), "%s", "1234567890");

        ret = snprintf(str, sizeof(str), "%s", "1234567890X");

        return 0;

}

以上代碼運作結果為:

3:abc => 3         // 沒有被截斷,輸出:abc

9:123456789 => 10  // 被截斷了,沒有輸出:1234567890

9:123456789 => 11  // 同樣被截斷了,沒有輸出:1234567890X

要點:

1) snprintf()第2個參數的大小,要求包含結尾符'\0';

2) snprintf()的傳回值,傳回的是期望大小,但不包含結尾符'\0'。有點拗口,這是什麼意思了?以示例來了解:

a) 當str為"abc"時,它期望的大小是3,"abc"的字元個數剛好是3;

b) 當str為"1234567890"時,它期望的大小是10,"1234567890"的字元個數剛好是10;

c) 當str為"1234567890X"時,它期望的大小是11,"1234567890X"的字元個數剛好是11。

以上示例,也可以看出:當snprintf()的傳回值大小等于或大于它的第二個參數值大小時,即發生了截斷。

有時候并不關是否有截斷,但是需要知道實際的大小,可以複用如下的實作:

// 函數fix_vsnprintf()的傳回值大小包含了結尾符'\0',其大小總是等于strlen(str)+1

int fix_vsnprintf(char *str, size_t size, const char *format, va_list ap)

    int expected = vsnprintf(str, size, format, ap);

    if (expected (size))

        return expected + 1; // 将結尾符也算進去

    return static_cast(size);

int fix_snprintf(char *str, size_t size, const char *format, ...)

    va_list ap;

    va_start(ap, format);

    int expected = fix_vsnprintf(str, size, format, ap);

    va_end(ap);

    return expected;

下面這個函數,在有些時候,也蠻友善的:

// 最多支援10240個ANSI字元,超過的會被截斷,但調用者可能不清楚是否發生了截斷@_@

std::string format_string(const char* format, ...)

    // size不包含結尾符,是以在配置設定記憶體時需要加一

    size_t size = 1024;

    char* buffer = new char[size + 1];

    // vsnprintf中的第二參數大小是要求包含結尾符的

    int expected = vsnprintf(buffer, size + 1, format, ap);

    if (expected >= ((int)size)+1)

    {

        // 防止太長,撐死記憶體

        if (expected > 10240)

            expected = 10240;

        // expected的大小不包含結尾符,是以在配置設定記憶體時需要加一

        delete []buffer;

        buffer = new char[expected + 1];

        va_end(ap);

        va_start(ap, format);

        vsnprintf(buffer, static_cast(expected + 1), format, ap);

    }

    DeleteHelper dh(buffer, true); // 釋放buffer所占記憶體

    return buffer;

繼續閱讀