snprintf的使用方法和陷阱

2021-09-28 17:27:00 字數 3475 閱讀 9976

snprintf()用於往buf中寫入格式化的字串。

想要正確地使用snprintf,需要對它的入參size和返回值的含義有準確的理解。否則會踩入深坑而不自知。

函式宣告:

int

snprintf

(char

*str, size_t size,

const

char

*format,..

.);

引數說明:

size:

snprintf往buf中最多寫入size個位元組。注意,字串結尾的』\0』也被計算在內。

返回值:

如果size足夠大,那麼函式返回值代表實際寫入的位元組數。(注意,字串結尾的』\0』不算在內)

如果size太小導致字串被截斷,那麼根據所使用glibc庫的版本,

從glibc version 2.1(發布於1999-02-03)開始:函式返回值代表欲寫入字串的原本長度(注意,』\0』不算在內)也就是說,如果返回值 大於等於size,那表明輸出的字串被截斷了。

glibc version 2.0.6(發布於1997-12-29):當字串被截斷時,函式返回 -1。

也就是說,對返回值進行檢查最穩妥的形式是:

int ret =

snprintf

(buf, size, format,..

.);if

(ret ==-1

|| ret >= size)

#include

#include

#define src_string "123456789abcdef|-+"

intmain()

;// 注意看,我故意把buf的size設小一點。為了體現坑。

char buf[10]

=;char guard2[10]

=;int ret =0;

int size =0;

memset

(guard1,

'*',

sizeof

(guard1)-1

);memset

(guard2,

'*',

sizeof

(guard2)-1

);printf

("guard1:%p buf:%p guard2:%p\n"

, guard1, buf, guard2)

;printf

("guard:[%s], buf[%s], guard2[%s]\n\n"

, guard1, buf, guard2)

; size =17;

ret =

snprintf

(buf, size, src_string)

;printf

("size=%d and sizeof(src_string) is %lu ret is %d\noutput is:[%s]\n\n"

, size,

sizeof

(src_string)

, ret, buf)

;memset

(buf,0,

sizeof

(buf));

size =18;

ret =

snprintf

(buf, size, src_string)

;printf

("size=%d and sizeof(src_string) is %lu ret is %d\noutput is:[%s]\n\n"

, size,

sizeof

(src_string)

, ret, buf)

;memset

(buf,0,

sizeof

(buf));

size =19;

ret =

snprintf

(buf, size, src_string)

;printf

("size=%d and sizeof(src_string) is %lu ret is %d\noutput is:[%s]\n\n"

, size,

sizeof

(src_string)

, ret, buf)

;printf

("guard:[%s], buf[%s], guard2[%s]\n"

, guard1, buf, guard2)

;return0;

}

tplink@ubuntu:~/testzone/snprintf_test$ gcc test.c 

tplink@ubuntu:~/testzone/snprintf_test$ ./a.out

guard1:0x7fff123872e0 buf:0x7fff123872f0 guard2:0x7fff12387300

guard:[*********], buf[

], guard2[*********]

size=17 and sizeof(src_string) is 19 ret is 18

output is:[123456789abcdef|

]#實際寫入了17位元組:前16個字元+1個'\0'

size=18 and sizeof(src_string) is 19 ret is 18

output is:[123456789abcdef|-]

#實際寫入了18位元組:前17個字元+1個'\0'

size=19 and sizeof(src_string) is 19 ret is 18

output is:[123456789abcdef|-+]

#實際寫入了19位元組:18個字元+1個'\0'

guard:[*********], buf[123456789abcdef|-+], guard2[-+]

回去看****示例,我故意把buf設為10個位元組長,但由於往snprintf中傳入的size分別為17、18、19,因此snprintf還是往buf中寫入了min(size, strlen(src_string) + 1)個位元組。也就是說發生了記憶體越界。

注意到guard2的起始位址在buf起始位址的16位元組後,當size=19時,snprintf往buf開始的位址寫入了18個字元+1個』\0』字元。於是guard2[0] = buf[16] = 『-』; guard2[1] = buf[17] = 『+』; guard2[3] = buf[18] = 『\0』;

設想要是我們的guard2儲存的是非常重要的資料,那麼記憶體月節後將會導致不可預知的嚴重後果。

所以關於snprintf的使用,務必要明確size引數的含義。如果min(size, strlen(src_string) + 1)比buf的實際尺寸大,將會導致記憶體越界。切記切記。

注:上述關於引數size和返回值的說明,對函式vsnprintf()也同樣適用。

snprintf 函式使用方法

眾所周知,sprintf不能檢查目標字串的長度,可能造成眾多安全問題,所以都會推薦使用snprintf.intsnprintf char str,size t size,constchar format,函式說明 最多從源串中拷貝size 1個字元到目標串中,然後再在後面加乙個0。所以如果目標串的大...

snprintf 函式使用方法

眾所周知,sprintf不能檢查目標字串的長度,可能造成眾多安全問題,所以都會推薦使用snprintf.自從snprintf代替了sprintf,相信大家對snprintf的使用都不會少,函式定義如下 intsnprintf char str,size t size,const char forma...

snprintf 函式使用方法

函式定義如下 int snprintf char str,size t size,constchar format,函式功能 先將可變引數 按照format的格式格式化為字串,然後再將其拷貝至dest str中。注意事項 如果格式化後的字串長度小於size,則將字串全部拷貝至dest str中,並在...