snprintf
這個(gè)函數(shù)是要指定長(zhǎng)度,而且編譯器會(huì)進(jìn)行越界檢查的,所以必須保證目標(biāo)長(zhǎng)度比所有參數(shù)加起來(lái)長(zhǎng)。可是考慮以下程序:
#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;
}
這個(gè)程式開(kāi)了-Wall
之後會(huì)報(bào)錯(cuò):
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
這個(gè)錯(cuò)誤是符合預(yù)期的,因?yàn)榇_實(shí)有可能越界。那麼問(wèn)題來(lái)了,我怎麼能完成同樣的功能但是不報(bào)錯(cuò)呢?
我的gcc
版本比較新,7.1.1
,估計(jì)老一點(diǎn)版本的編譯器不會(huì)報(bào)這個(gè)錯(cuò)誤。
首先snprintf()
的第二個(gè)參數(shù)代表的是緩衝區(qū)的大小,在這裡應(yīng)該是LENGTH
,sizeof(LENGTH)
的值是4
(我猜你想寫(xiě)的應(yīng)該是size (cache)
吧)。那麼,改成snprintf(cache, LENGTH, "%s/ruaruarua", cache);
之後就行了嗎?我們來(lái)看看這個(gè)例子:
#include <stdio.h>
int main()
{
char buf[20] = "hello";
snprintf(buf, 20, "%s world", buf);
puts(buf);
return 0;
}
這個(gè)範(fàn)例企圖給buf
末尾加上一個(gè)字串,看看輸出
world
並沒(méi)有達(dá)到期望的結(jié)果。這是為什麼呢? snprintf()
的手冊(cè)裡有這麼一段:
的緩衝區(qū)設(shè)為數(shù)組中字串的結(jié)尾:Some programs imprudently rely on code such as the following
sprintf(buf, "%s some further text", buf);
to append text to
家族的函數(shù)執(zhí)行結(jié)果將是未定義的。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.
即如果原始和目標(biāo)緩衝區(qū)重疊的話,這些
printf()snprintf()
那該如何「向一個(gè)陣列中印出自己原有的內(nèi)容和一些新的內(nèi)容」呢?一種方式是把傳給
snprintf(buf + strlen(buf), 20, " world");
那如何連續(xù)往緩衝區(qū)末端新增資料呢?注意到
printf()家族的函數(shù)回傳值都是列印的字元數(shù)(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;
}
結(jié)果為
hello world
hello again