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

printf 參數類型不匹配陷阱:浮點數傳入 %ld 的未定義行為演示

     編輯:關於C語言

陷阱代碼


float n1 = 3.0;
double n2 = 3.0;
long n3 = 2000000000;
long n4 = 1234567890;
long n5 = 250;
long n6 = 213;

printf("%ld %ld %ld %ld %ld %ld\n", n1, n2, n3, n4, n5, n6);

現象分析

  1. 默認參數提升:float 以 double 傳遞(佔 2 個 32 位棧槽 / 1 個 64 位寄存器)。
  2. 格式字符串欺騙:%ld 告訴 printf「下一個參數是 long(整數)」。
  3. 棧/寄存器解讀錯誤:
    • x86-64 (System V AMD64 ABI):前 6 個整數/指針參數通過 RDI, RSI, RDX, RCX, R8, R9 傳遞;浮點參數通過 XMM0~XMM7。printf 讀整數寄存器,但浮點值在 XMM 寄存器 → 讀到垃圾值。
    • i386 (cdecl):所有參數壓棧。float 壓 8 字節 (double),%ld 讀 4 字節 → 讀到 double 低 4 字節(通常為 0),棧指針錯位導致後續參數全部錯位。
  4. 結果:n5、n6 輸出不可預測(垃圾值、錯位值),屬於未定義行為 (UB)。

正確做法

類型正確格式說明
float/double%f, %e, %gfloat 自動提升為 double
long%ld
long long%lld
int64_t%" PRId64 "需 <inttypes.h>
指針%p配合 (void *)

編譯器保護

  • GCC/Clang -Wformat -Wformat-security(-Wall 含之)會報警:format '%ld' expects argument of type 'long int', but argument 1 has type 'double'。
  • 務必開啟警告並視為錯誤 (-Werror=format),編譯期攔截此類 Bug。

變參函數類型安全本質

printf 運行時無法感知實際參數類型,完全依賴格式字符串。調用者必須保證格式與實參類型一一對應。C 語言不提供運行時類型檢查,這就是「不安全」的根源。

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