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
,估計老一點版本的編譯器不會報這個錯誤。
PHP中文网2017-05-27 17:46:46
首先snprintf()
的第二個參數代表的是緩衝區的大小,在這裡應該是LENGTH
,sizeof(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 callingsprintf()
,(),
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