#include <stdio.h>
int array[] = {23, 34, 12, 17, 204, 99, 16};
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int main(void) {
int d = -1, x;
if (d <= TOTAL_ELEMENTS - 2) // 這裡藏著巨坑!
x = array[d + 1]; // 永遠不會被執行
return 0;
}
為什麼 x = array[d + 1]; 永遠不會執行?經調試發現,if 判斷後直接跳過。根本原因在於 隱式類型轉換:
sizeof 回傳 size_t(無號整數,通常為 unsigned int 或 unsigned long)。TOTAL_ELEMENTS 為無號整數,d 為有號 int(-1)。d 被隱式轉換為無號整數,-1 變成極大的正數(如 0xFFFFFFFF),導致條件永假。這類 Bug 隱蔽且破壞力強,極難靠單純除錯發現,必須從語言規則層面理解。
char、short int 先轉為 int;float 轉為 double。double 皆轉 double;有 long 皆轉 long;有 unsigned 皆轉 unsigned。所有 char、short int、位段,優先轉為 int;若 int 無法表示原類型所有值,則轉為 unsigned int。
表達式求值時,通常將「低類型」(表示範圍較小)轉為「高類型」。但 float 不再強制升為 double,若單精度計算結果與雙精度一致,編譯器可選擇不轉換(現代編譯器多不支援此優化)。
當運算元包含有號與無號類型時,轉換遵循「類型等級」與「表示範圍」雙重判斷:
unsigned long int → 另一個轉為 unsigned long int。long int,另一個是 unsigned int:
long int 能完整表示 unsigned int 範圍 → 轉為 long int;unsigned long int。unsigned int,另一個是 int → int 轉為 unsigned int。假設 int 16 位,long int 32 位:
-1L < 1U:-1L 為 signed long,1U 為 unsigned int。因 signed long 可完整表示 unsigned int 範圍,1U 轉為 signed long,比較結果為真(-1 < 1)。-1L > 1UL:1UL 為 unsigned long,-1L 轉為 unsigned long(極大正數),比較結果為真(0xFFFFFFFF > 1)。sizeof、陣列索引、迴圈邊界等常見場景。-Wsign-compare)、Clang Static Analyzer、Coverity 等可捕獲大多數隱式轉換問題。(int)sizeof(...) 或 (size_t)d 使意圖顯性化。C 語言的隱式類型轉換規則看似繁瑣,實則遵循「保值」與「自然擴展」原則。深入理解這套機制,不僅能避開經典陷阱,更能在底層系統程式設計中精準控制資料表示與運算行為。下次寫 if (i < sizeof(arr)) 時,請三思:i 的類型是否與 sizeof 回傳類型一致?