類型提升是 C 編譯器在表達式求值時自動進行的隱式類型轉換。根據 ANSI C 標準,某些類型在參與運算前會被「提升」為更寬的類型,確保運算在統一精度下進行,防止溢出或精度損失。
| 原始類型 | 通常提升為 | 備註 |
|---|---|---|
char、signed char、unsigned char | int | 若 int 無法表示所有值則提升為 unsigned int |
short、unsigned short | int | 同理 |
| 位域、枚舉類型 | int | 整數提升範圍 |
float | double | 浮點數提升 |
| 數組類型 | 指向元素類型的指針 | 退化為指針 |
| 函數類型 | 指向函數的指針 | 函數名自動轉換 |
所有窄於 int 的整數類型(char、short、位域、枚舉及其有符號/無符號版本)在表達式中自動提升為 int。若 int 無法表示原類型所有值(如 16 位系統上 unsigned short 範圍 0~65535 超過 int 最大值 32767),則提升為 unsigned int。
char c1 = 200, c2 = 100;
int result = c1 + c2; // c1、c2 先提升為 int 再相加,結果 300
// 若無提升,char 相加可能溢出(假設 char 為 8 位有符號,最大 127)
float 在表達式中自動提升為 double。這意味著 float 變量參與運算時實際以雙精度計算,結果再截斷存回 float。
float f1 = 1.0f, f2 = 2.0f;
double d = 3.0;
f1 = f2 * d; // f2 提升為 double,與 d 進行雙精度乘法,結果轉為 float 存入 f1
printf("%zu\n", sizeof('A')); // 輸出 4(假設 int 為 4 字節),而非 1
// 原因:字符字面量 'A' 在 C 中類型為 int,非 char!
C 與 C++ 差異:C++ 中字符字面量類型為char,故sizeof('A') == 1。
執行
c1 = c1 + c2;時,「整數提升」要求抽象機器將每個變量值提升為int大小,相加後再截斷。只要兩個char相加不會產生溢出異常,實際執行只需產生相同結果,可省略提升步驟。同理,
f1 = f2 * d;中乘法可用單精度執行,若編譯器能證明結果與雙精度相同(如d為常量2.0)。
函數調用屬於表達式,因此參數傳遞同樣發生提升:
char/short → intfloat → double這也是早期 K&R C 中函數聲明無參數類型仍能工作的原因——調用方自動提升,被調用方按提升後類型取值。
sizeof('x') == 1 → ✅ C 中為 sizeof(int)unsigned char uc = 200; if (uc > 100) ... 中 uc 提升為 int,比較正確;但涉及有符號/無符號混合運算需極度小心-Wconversion 編譯選項檢測隱式轉換(long)a * b 避免溢出C++ 修改了字符字面量類型為 char,且引入函數重載、模板等機制,類型系統更嚴格。但整數/浮點數提升規則基本兼容 C。