C 語言整數類型轉換規則是 Bug 溫床。本文通過代碼實驗演示轉換規則、溢出行為及補碼表示特性。
#include#include int main() { // 1. 整數字面值溢出 int i = 200 * 300 * 400 * 500; // 12,000,000,000 > INT_MAX(2,147,483,647) printf("i = %d\n", i); // 輸出負數 (補碼截斷) // 2. 浮點數精度陷阱 float j1 = (3.14 + 1e20) - 1e20; // 1e20 精度吞沒 3.14 → 0.0 float j2 = 3.14 + (1e20 - 1e20); // 結合順序改變 → 3.14 printf("j1 = %f, j2 = %f\n", j1, j2); // 3. 無符號最大值與 -1 補碼相同 unsigned int u = UINT_MAX; // 4294967295 (0xFFFFFFFF) int tu = (int)u; // -1 (補碼 0xFFFFFFFF) printf("u = %u, tu = %d\n", u, tu); // 輸出: u = 4294967295, tu = -1 // 4. 有符號轉無符號:負數變大正數 short v = -12345; unsigned short uv = (unsigned short)v; // 位模式不變: 0xCFC7 printf("v = %d, uv = %u\n", v, uv); // uv = 53191 (65536 - 12345) // 5. 表達式隱式轉換陷阱 // 若一邊無符號,另一邊有符號 → 有符號隱式轉無符號 // -1 < 0U → -1 轉為 4294967295U,比較結果為假 (0) ❌ // 6. 短整型溢出行為 (補碼環細) short a = -65536; // 0x0000 (截斷) short b = -1; // 0xFFFF printf("a+b = %d\n", a+b); // 0xFFFF + 0x0000 = 0xFFFF = -1 return 0; }
unsigned 類型 → **整個表達式提升為無符號類型** 進行計算/比較。-1 > 0U 為真 (因 -1 變為巨大無符號數)。-Wsign-compare (在 -Wall 中)。公式:U(x) = (x >= 0) ? x : x + 2^w (w 為目標類型位寬)。
short -1 → unsigned short 65535)。公式:T(x) = (x < 2^{w-1}) ? x : x - 2^w。
UINT_MAX → -1)。x+1 > x 恆真)。// 檢測 a + b 是否溢出 (有符號 int)
int safe_add(int a, int b, int *result) {
if (b > 0 && a > INT_MAX - b) return 0; // 正溢出
if (b < 0 && a < INT_MIN - b) return 0; // 負溢出
*result = a + b;
return 1;
}
size_t)。(unsigned)a < b 或 (int)b > a。-fwrapv (GCC/Clang) 強制有符號溢出環繞語義,若代碼依賴此行為 (如某些哈希算法)。