linux - 如何使用 snprintf 向一個陣列中列印自己原有的內容和一些新的內容?
仅有的幸福
仅有的幸福 2017-05-27 17:44:46
0
1
876

snprintf這個函數是要指定長度,而且編譯器會進行越界檢查的,所以必須保證目標長度比所有參數加起來長。可是考慮以下程序:

#include <stdio.h>
#include <string.h>

#define LENGTH 1024

int main() {
    char cache[LENGTH];
    memset(cache, 0, LENGTH);
    snprintf(cache, sizeof(LENGTH), "%s/ruaruarua", cache);
    return 0;
}

這個程式開了-Wall之後會報錯:

test.c: In function ‘main’:
test.c:9:44: error: ‘/ruaruarua’ directive output truncated writing 10 bytes into a region of size 4 [-Werror=format-truncation=]
     snprintf(cache, sizeof(LENGTH), "%s/ruaruarua", cache);
                                        ~~~~^~~~~~
test.c:9:5: note: ‘snprintf’ output 11 or more bytes into a destination of size 4
     snprintf(cache, sizeof(LENGTH), "%s/ruaruarua", cache);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors

這個錯誤是符合預期的,因為確實有可能越界。那麼問題來了,我怎麼能完成同樣的功能但是不報錯呢?

我的gcc版本比較新,7.1.1,估計老一點版本的編譯器不會報這個錯誤。

仅有的幸福
仅有的幸福

全部回覆(1)
洪涛

首先snprintf()的第二個參數代表的是緩衝區的大小,在這裡應該是LENGTHsizeof(LENGTH)的值是4
(我猜你想寫的應該是size (cache)吧)。那麼,改成snprintf(cache, LENGTH, "%s/ruaruarua", cache);之後就行了嗎?我們來看看這個例子:

#include <stdio.h>

int main()
{
    char buf[20] = "hello";
    snprintf(buf, 20, "%s world", buf);
    puts(buf);
    return 0;
}

這個範例企圖給buf末尾加上一個字串,看看輸出


 world

並沒有達到期望的結果。這是為什麼呢? snprintf()的手冊裡有這麼一段:

Some programs imprudently rely on code such as the following

sprintf(buf, "%s some further text", buf);

to append text to buf. However, the standards explicitly note that the results are undefined if source and destination buffers overlap when calling sprintf(), (), vsnprintf( ). Depending on the version of gcc(1) used, and the compiler options employed, calls such as the above will not produce the expected results. 即如果原始和目標緩衝區重疊的話,這些printf()

家族的函數執行結果將是未定義的。

那該如何「向一個陣列中印出自己原有的內容和一些新的內容」呢?一種方式是把傳給

snprintf()
的緩衝區設為數組中字串的結尾:

snprintf(buf + strlen(buf), 20, " world");
那如何連續往緩衝區末端新增資料呢?注意到printf()家族的函數回傳值都是列印的字元數(number of characters printed),那麼可以這麼呼叫:

#include <stdio.h>
#include <string.h>

int main()
{
    char buf[40];
    char *p = buf;

    p += sprintf(p, "hello %s\n", "world");
    p += sprintf(p, "hello %s", "again");
    /* and more similar calls... */

    puts(buf);
    return 0;
}
結果為
hello world
hello again
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板