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

C 語言進階:深度解剖 signed/unsigned 與整數溢出機制(上)

     編輯:關於C語言

C 語言基本類型可通過修飾符組合:signed、unsigned、long、short。本文聚焦 signed/unsigned 與 int 的交互機制,從二進制存儲、補碼表示、溢出行為三個維度深度剖析,打破「有符號/無符號只是範圍不同」的表層認知。

一、 類型修飾符速查

修飾符含義可修飾類型默認規則
signed有符號char、intint 默認有符號
unsigned無符號char、int-
long長型int、double-
short短型int-

二、 核心概念:什麼是溢出?

計算機為類型分配固定位寬(如 32 位 int),位模式總數有限(2^32 種),因此可表示值有上下界。超出邊界即發生溢出。關鍵問題:溢出時位模式如何解釋?

三、 無符號整型 unsigned int(以 16 位 unsigned short 為例)

  • 位寬:16 位
  • 取值範圍:0 ~ 65535 (2^16 - 1)
  • 二進制結構:所有位均為數值位,最高位(MSB)參與數值計算
  • 溢出行為:模 2^N 環狀繞回(C 標準保證)

實驗驗證

unsigned short a = 32767;  // 0111 1111 1111 1111 (0x7FFF)
unsigned short b = a + 1;  // 1000 0000 0000 0000 (0x8000) = 32768
unsigned short c = a + 2;  // 1000 0000 0000 0001 (0x8001) = 32769
// ...
unsigned short max = 65535; // 1111 1111 1111 1111 (0xFFFF)
unsigned short wrap = max + 1; // 0000 0000 0000 0000 = 0

無符號溢出演示

結論:無符號類型無溢出未定義行為,保證模 2^N 算術,最高位為 1 時單純表示大數值(如 0x8000 = 32768)。

四、 有符號整型 signed int(以 16 位 short 為例)

  • 位寬:16 位
  • 取值範圍:-32768 ~ 32767
  • 二進制結構:最高位為符號位(0 正、1 負),其餘 15 位為數值位
  • 負數存儲:二進制補碼形式

補碼運算規則(核心)

  1. 原碼:符號位 + 絕對值二進制(如 -6:1 00000000000110)
  2. 反碼:符號位不變,數值位按位取反(-6:1 11111111111001)
  3. 補碼:反碼 + 1(-6:1 11111111111010) → 計算機實際存儲形式

關鍵驗證程序

short a = 32767;  // 0111 1111 1111 1111 (0x7FFF)
short b = a + 1;  // 1000 0000 0000 0000 (0x8000) = -32768
short c = a + 2;  // 1000 0000 0000 0001 (0x8001) = -32767
short d = a + 3;  // 1000 0000 0000 0010 (0x8002) = -32766

有符號溢出演示

結果解析

表達式二進制(補碼)十進制值解釋
a0111 1111 1111 111132767最大正數
b = a+11000 0000 0000 0000-32768最小負數(補碼特有)
c = a+21000 0000 0000 0001-32767補碼:-(2^15 - 1)
d = a+31000 0000 0000 0010-32766補碼:-(2^15 - 2)

補碼轉十進制兩種等價方法

方法一:減一取反法

c = 0x8001
減一: 0x8000
取反: 0x7FFF = 32767
符號位 1 → -32767

方法二:權重求和法(推薦,避免原碼概念)

c = 0x8001 (32位擴展: 0xFFFF8001)
= -2^15 + 2^0 = -32768 + 1 = -32767
// 最高位權重為 -2^(N-1),其餘位權重為 +2^i

五、 環狀數軸直觀理解

有符號 16 位範圍 [-32768, 32767] 可視為環狀:

  32767 → -32768 → -32767 → ... → -1 → 0 → 1 → ... → 32767
   ↑                                                           ↓
   └───────────────────────────────────────────────────────────┘
                    加 1 繞回,減 1 逆向繞回

六、 關鍵差異總結

特性無符號有符號
最高位含義數值位 (2^(N-1))符號位 (0正/1負)
溢出語義定義行為:模 2^N 環繞未定義行為 (C標準)
最大值2^N - 12^(N-1) - 1
最小值0-2^(N-1)
位模式 0x800032768-32768
位模式 0xFFFF65535-1

七、 實戰警示

  1. 有符號溢出是 UB:編譯器可假設不發生,導致優化刪除檢查代碼(如 if (a+1 > a) 被優化為 true)
  2. 混合運算隱式轉換:unsigned + signed → signed 隱式轉為 unsigned,負數變巨大正數
  3. 循環邊界陷阱:for (unsigned i = n; i >= 0; --i) 永真(i 永不 < 0)
  4. 調試技巧:gcc -fwrapv 強制有符號環繞語義;-fsanitize=undefined 運行時檢測 UB

下一篇將深入剖析 char 類型的符號性、signed char/unsigned char 區別、字符字面量類型、以及更複雜的混合運算陷阱。

本文出自 “趙玉強的博客”,謝絕轉載!

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