在 C 語言中,printf 系列函數的格式字符串與實際參數必須嚴格匹配,否則會觸發未定義行為(UB),導致程式輸出錯誤數值甚至崩潰。本文通過實測代碼演示 %f 對應 int 及 %d 對應 double 時的具體後果,並解析底層原因。
/* test.c 編譯:gcc test.c -o test */
#include <stdio.h>
int main(void) {
printf("%f\n", 5); // %f 期望 double(8 bytes),實傳 int(4 bytes)
printf("%d\n", 5.01); // %d 期望 int(4 bytes),實傳 double(8 bytes)
return 0;
}
0.000000 1889785610
%f 配 int → 輸出 0.0000005 放入 RDI,而 printf 內部按 %f 從 XMM0 讀取。此時 XMM0 內容為殘留值(通常為 0),故輸出 0.000000。%d 配 double → 輸出 18897856105.01 的 IEEE-754 二進制佈局為 0x401428F5C28F5C29。調用者將低 32 位 0xC28F5C29 放入 XMM0,高 32 位 0x401428F5 放入 XMM1。printf 讀取 RDI(整數參數寄存器)時拿到的是棧上殘留值或垃圾數據,經實測恰好解析為 1889785610(0x709A8C1A)。-Wall -Wextra -Wformat=2(GCC/Clang)可在編譯期捕獲絕大多數不匹配。std::format (C++20) 或 fmt 庫;C11 可配合 _Generic 實現類型安全封裝。核心結論:C 語言不提供運行時類型檢查,格式字符串與參數不匹配屬於未定義行為,後果不可預測,必須在編譯期靜態消除。