調用格式
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *buf, const char *format, ...);
int snprintf(char *buf, size_t n, const char *format, ...); // 安全版
格式字符串解剖
%[flags][width][.precision][length]specifier
轉換說明符完整表
| 符號 | 輸出類型 | 對應參數類型 | 示例 |
%d, %i | 有符號十進制整數 | int | 42, -7 |
%u | 無符號十進制整數 | unsigned int | 42 |
%o | 八進制 (無前綴) | unsigned int | 52 |
%x, %X | 十六進制 (小寫/大寫) | unsigned int | 2a, 2A |
%f, %F | 定點小數 | double (float 升級) | 3.141593 |
%e, %E | 科學記數法 (e/E) | double | 3.141593e+00 |
%g, %G | 自動選擇 %f/%e (短者勝出) | double | 3.14159 |
%a, %A | 十六進制浮點數 (C99) | double | 0x1.921fbp+1 |
%c | 單字元 | int (字元碼) | A |
%s | 字串 | const char* | hello |
%p | 指針地址 | void* | 0x7ffe... |
%n | 不輸出,寫入已輸出字元數 | int* | - |
%% | 輸出字面 % | - | % |
標志
| 標志 | 含義 | 示例 |
- | 左對齊 (默認右對齊) | %-10s → "hello " |
+ | 有符號數總顯示符號 | %+d → +42, -7 |
(空格) | 正數前加空格,負數加 - | % d → 42, -7 |
# | 替代形式:%#o 加 0, %#x 加 0x, %#f/%e/%g 強制保留小數點 | %#x → 0x2a |
0 | 右對齊時用 0 填充 (數值類型) | %06d → 000042 |
寬度與精度
- 寬度:最小輸出字元數,不足填充。
%10d、%*d (參數指定)
- 精度:
- 整數:最小數字位數,不足前補 0 (
%.4d → 0042)
- 浮點:小數點後位數 (
%.2f → 3.14)
- 字串:最大字元數 (
%.3s → hel)
- 組合:
%8.3f (寬 8,小數 3),%-10.2s (左對齊寬 10,最多 2 字元)
長度修飾符
| 修飾符 | 含義 | 適用類型 |
hh | char (1B) | %hhd, %hhu |
h | short (2B) | %hd, %hu |
l | long (4/8B) / double (for %f) | %ld, %lf |
ll | long long (8B) | %lld, %llu, %llx |
L | long double | %Lf, %Le |
j | intmax_t / uintmax_t | %jd, %ju |
z | size_t | %zu, %zd |
t | ptrdiff_t | %td, %tu |
經典組合示例
// 對齊表格
printf("%-20s %10d %8.2f\n", "Apple", 100, 5.50); // 左對齊字串,右對齊數字
// 十六進制轉儲
printf("0x%08X\n", 0x123ABC); // 0x00123ABC
// 指針打印 (標準)
printf("%p\n", (void*)ptr);
// size_t 打印 (可移植)
printf("Size: %zu bytes\n", sizeof(arr));
// int64_t 打印 (C99 )
#include
printf("Big: %" PRId64 "\n", big_num);
安全與最佳實踐
- 嚴禁格式字串漏洞:
printf(user_input) → printf("%s", user_input)
- 優先用 snprintf:防緩衝區溢出
- 參數類型嚴格匹配:啟用
-Wformat -Wformat-security 編譯器檢查
%lf 在 printf 中等同 %f (C99 允許),但 scanf 必須用 %lf 讀 double
%p 必須轉換為 void*:printf("%p", (void*)ptr)
總結
printf 格式化字串是聲明式輸出規範,掌握「標志-寬度-精度-長度-類型」五段式語法,能精確控制任何輸出格式。現代代碼應配合 使用定寬整數宏 (PRId32, PRIu64...) 確保跨平台可移植,並堅持 snprintf 防溢出。