首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言格式化輸出函數族全解析:printf/sprintf/snprintf 安全使用指南

     編輯:關於C

函數族譜系

函數輸出目標參數形式備註
printfstdout可變參數
fprintfFILE*可變參數
sprintfchar* buf可變參數不安全,無長度限制
snprintfchar* buf可變參數 + size安全,限制寫入長度
vprintfstdoutva_list
vfprintfFILE*va_list
vsprintfchar* bufva_list不安全
vsnprintfchar* bufva_list + size安全

返回值規則

  • 成功:返回**寫入字符數**(不含結束符 \0)。
  • 失敗:返回負值。
  • snprintf/vsnprintf 特殊:若緩衝區太小導致截斷,返回**本應寫入的完整長度**(不含 \0),而非實際寫入數。可用於預計算所需緩衝區大小。
char buf[10];
int len = snprintf(buf, 10, "%s$", "1234567890123"); 
// len = 13 (實際字符串長度), buf = "123456789" (9字符+\0)

三大使用禁區與最佳實踐

1. 緩衝區溢出風險 —— 棄用 sprintf/vsprintf

sprintf 不檢查目標緩衝區大小,極易導致棧溢出、任意代碼執行漏洞。

強制規範:永遠使用 snprintf/vsnprintf,並傳入正確的 size(通常為 sizeof(buf))。

2. 源目標重疊未定義行為

sprintf(buf, "%s append", buf); // 未定義行為!

C 標準明確規定:sprintf/snprintf/vsprintf/vsnprintf 的源字符串(參數)與目標緩衝區**重疊時行為未定義**。

正確做法:使用臨時緩衝區或 memmove 錯開內存。

3. 格式化字符串漏洞 —— 禁止 printf(user_str)

printf(user_input); // 危險!若 user_input 含 "%n" 可任意寫內存

%n 將已輸出字符數寫入對應指針參數。攻擊者構造 "%n%n%n" 可修改關鍵內存(如返回地址、函數指針)。

鐵律:格式化字符串必須為字面量或可信常量。正確:printf("%s", user_input);。

其他注意事項

  • va_list 類型變量在 va_start 後、va_end 前有效,va_end 後狀態未定義,不可復用。
  • 傳遞 char* 給 %s 時必須確保以 \0 結尾,否則越界讀取。
  • 浮點數默認提升為 double,%f 對應 double,float 也可用 %f(自動提升)。

總結

掌握 printf 族函數的返回值語義、緩衝區管理、重疊未定義行為、格式化字符串漏洞,是編寫安全、健壯 C 代碼的基本功。原則:默認用 snprintf,格式串硬編碼,拒絕 sprintf。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved