首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C語言無符號整數運算陷阱:為什麼 `i * -1` 不會先將 -1 轉為 4294967295?

     編輯:程式設計綜合問答

問題背景

在 C 語言中,當有符號整數與無符號整數進行運算時,會發生「整數提升」與「通常算術轉換」。許多初學者會誤以為編譯器會先將字面常數 -1 轉換為無符號數 4294967295(假設 32 位元),再與無符號變數 i 相乘。實際上情況更微妙,理解這一點對避免溢位 Bug 至關重要。

程式碼示例

#include <stdio.h>

int main() {
    unsigned int i = 3;
    printf("%u\n", i * -1); // 輸出 4294967293
    return 0;
}

核心解析

關鍵在於運算子優先級與類型轉換規則:

  1. -1 是 int 型別的負數常數(補碼表示為 0xFFFFFFFF)。
  2. 根據 C 標準的「通常算術轉換」,當 unsigned int 與 int 運算時,int 會被轉換為 unsigned int。此時 -1 變成 4294967295U。
  3. 乘法運算在 unsigned int 域內進行:3 * 4294967295U = 12884901885。
  4. 結果超出 32 位元無符號整數範圍(0 ~ 4294967295),發生模 2^32 截斷,保留低 32 位:12884901885 % 4294967296 = 4294967293(即 0xFFFFFFFD)。

所以「不是先轉再乘」,而是「轉換發生在運算子評估之前,運算本身在無符號域內完成,最後截斷」。

最佳實務建議

  • 避免在同一表達式中混用有號與無號型別。
  • 若需負數運算,請確保所有運算元皆為有號型別,或顯式轉型:(int)i * -1。
  • 開啟編譯器警告(如 -Wsign-conversion),可在編譯期捕捉隱式轉換風險。

總結

輸出 4294967293 是無符號整數模運算的必然結果。掌握整數提升與轉換規則,才能寫出可攜帶、無 Bug 的 C 程式碼。

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