#include <stdio.h>
// 標準輸出流
int printf(const char *format, ...);
int vprintf(const char *format, va_list ap);
// 指定流輸出
int fprintf(FILE *stream, const char *format, ...);
int vfprintf(FILE *stream, const char *format, va_list ap);
// 字符串輸出
int sprintf(char *str, const char *format, ...);
int vsprintf(char *str, const char *format, va_list ap);
// 安全字符串輸出 (防緩衝區溢出)
int snprintf(char *str, size_t size, const char *format, ...);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
| 函數組 | 輸出目標 | 參數機制 | 安全性 | 典型應用場景 |
|---|---|---|---|---|
| printf / vprintf | stdout (標準輸出) | 可變參數 / va_list | - | 控制台日誌、調試輸出 |
| fprintf / vfprintf | FILE *stream (文件/網絡/管道) | 可變參數 / va_list | - | 文件寫入、錯誤日誌(stderr) |
| sprintf / vsprintf | char *str (字符串緩衝區) | 可變參數 / va_list | ⚠️ 不安全,無長度檢查 | 舊代碼、確定緩衝區足夠大時 |
| snprintf / vsnprintf | char *str, size_t size | 可變參數 / va_list | ✅ 安全,限制寫入長度 | 現代代碼標準選擇,防止緩衝區溢出 |
size-1,函數會截斷並寫入 '\0',返回值為本應寫入的字符數(不含 '\0')。若返回值 >= size,表示發生截斷。man 手冊原文解讀:
"Upon successful return, these functions return the number of characters printed (not including the trailing '\0' used to end output to strings). The functions snprintf() and vsnprintf() do not write more than size bytes (including the trailing '\0'). If the output was truncated due to this limit then the return value is the number of characters (not including the trailing '\0') which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated."
vprintf 等函數接收 va_list 參數,用於實現自定義格式化輸出包裝器。例如實現一個帶時間戳的日誌函數:
void log_msg(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
fprintf(stderr, "[LOG] ");
vfprintf(stderr, fmt, args); // 核心:將可變參數傳遞給 vfprintf
fprintf(stderr, "\n");
va_end(args);
}
%[flags][width][.precision][length]specifier
d/i(有符號整數) u(無符號) x/X(十六進制) f/F(浮點) s(字符串) c(字符) p(指針地址) %(字面%)hh(char) h(short) l(long/double) ll(long long) L(long double) z(size_t) t(ptrdiff_t)printf(user_input))。size_t、ptrdiff_t 等類型,使用 %zu、%td (C99)。printf 往往需重寫 fputc 實現串口輸出。掌握 printf 家族的輸出目標差異、參數傳遞機制、返回值精確語義及安全性層級,是編寫健壯 C/C++ 代碼的基本功。現代開發中,snprintf 應成為字符串格式化的首選。