C語言格式化輸出函數及使用禁區
編譯環境:
Debian: 7.6
gcc: 4.7.2
一、格式化輸出函數
C語言中設計到的標准格式化輸出函數如下:
#include
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
#include
int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
二、相互之間的關系
1、共同點:
在格式化字串的控制下,把數據輸出到輸出設備。格式化字串指定如何把後續的參數進行轉化。如:
printf("%02x", 100); /* 輸出是16進制 */
printf("%dx", 100); /* 輸出是10進制 */
2、不同點:
按輸出到的設備分:
printf()
vprintf()
輸出
至標准輸出流stdout
fprintf()
vfprintf()
輸出
至指定輸出流
sprintf()
snprintf()
vsprintf()
vsnprintf()
輸出
至字串str
按是否指定操作字節分:
snprintf()
vsnprintf()
寫入至多size個字節(含'\0')到dtr
vprintf()
vfprintf()
vsprintf()
vsnprintf()
分別等同於:printf()
fprintf()
sprintf()
snprintf()
區別是:它們都有va_list列表,一旦調用完畢,ap即成為“未定義”狀態
3、返回值:
正常情況下,函數返回輸出成功的字符個數(不含'\0')。若出錯,返回負值。
snprintf()和vsnprintf()輸出字符個數不超過size字節(含'\0'),
如果size小於字符串的長度(不含'\0'),字符串會被截斷,返回值是字符串的長度(不含'\0'),如下:
int len;
char str_buf[100];
len = snprintf(buf, 10, "%s$", "1234567890123");
// len: 13, buf: "1234567890"
如果size大於數據緩沖區長度,緩沖區長度個字串會被復制,返回值是字符串的長度(不含'\0'),如下:
char str_buf[5];
// len: 13, buf: "12345"
三、使用注意
1、在使用sprintf()和vsprintf()的時候,應確保數據大小不超出str緩沖區的大小,否則產生溢出,造成災難。如果無法保證,應該選用snprintf()和vsnprintf()。
2、把字串加到原字串的後面,如下:
sprintf(buf, "%s append text", buf);
在我用的gcc中,這種使用如期運行;但是,在有的gcc版本中,結果並不正確。所以,不要這樣做。
而且,標准中明確指出,調用sprintf(), snprintf(), vsprintf(),vsnprintf()函數,如果源、目標地址重疊,結果是未定義的(undefined).
3、像這樣的代碼printf(foo);往往會引入bug。因為如果foo中包含“%n”將引起printf()對內存的寫入並造成安全漏洞。例如:
printf("%n"); // Segmentation fault