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

C語言有符號與無符號整數加法的隱式轉換陷阱

     編輯:關於C語言

C語言有符號與無符號整數加法的隱式轉換陷阱

看似簡單的unsigned int + int運算,隱藏著許多資深工程師也會踩的坑。通過兩道題目揭示整數提升與無符號轉換規則。

題目一

unsigned int a = 6;
int b = -20;
printf("%d\n", a + b);           // 輸出?
(a + b) > 6 ? puts(">6") : puts("<=6");  // 判斷?

答案:>6

題目二

unsigned int a = 6;
int b = -2;
printf("%d\n", a + b);           // 輸出?
(a + b) > 6 ? puts(">6") : puts("<=6");  // 判斷?

答案:<=6

核心規則:整數提升與 usual arithmetic conversions

  1. 無符號等級高於有符號:unsigned int等級 ≥ int,運算時int隱式轉換為unsigned int
  2. 負數轉無符號:保持位模式不變:按補碼位模式直接重新解釋為無符號值
  3. 運算在無符號域進行:結果類型為unsigned int,溢出按模2ⁿ環繞

詳細推導

題目一:6 + (-20)

  • -20的32位補碼:0xFFFFFFEC(4294967276)
  • 轉為unsigned int:4294967276
  • 無符號加法:6 + 4294967276 = 4294967282(0xFFFFFFF2)
  • printf("%d")按有符號解釋:-14
  • 比較(a+b) > 6:左邊無符號4294967282,右邊6提升為無符號 → true

題目二:6 + (-2)

  • -2的補碼:0xFFFFFFFE(4294967294)
  • 無符號加法:6 + 4294967294 = 4294967300 → 溢出環繞 → 4(0x00000004)
  • printf("%d")輸出:4
  • 比較4 > 6 → false

關鍵洞察

最高位溢出位被丟棄是題目二結果為4而非巨大數值的原因。無符號加法模2³²運算,進位位直接丟失:

  0000...0110  (6)
+ 1111...1110  (-2 as unsigned 4294967294)
= 10000...0100  → 截取低32位 → 0000...0100 (4)

避坑指南

  1. 避免混合有符號/無符號運算,特別是比較運算
  2. 若必須混合,顯式轉型到有符號長整型:(long)a + b
  3. 編譯器警告-Wsign-compare、-Wsign-conversion務必開啟
  4. 理解%d與%u只影響輸出格式,不改變內存位模式

標準依據

C99 §6.3.1.3/6.3.1.8:當有符號與無符號同寬度運算時,有符號轉無符號;轉換保持二進制位模式不變(即補碼直接重新解釋)。

這兩道題精準暴露了「直覺以為是6-20=-14,比較時按有符號邏輯」與「實際按無符號模運算」的認知鴻溝。計算機不講直覺,只講位模式。

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