C 語言基本類型可通過修飾符組合:signed、unsigned、long、short。本文聚焦 signed/unsigned 與 int 的交互機制,從二進制存儲、補碼表示、溢出行為三個維度深度剖析,打破「有符號/無符號只是範圍不同」的表層認知。
| 修飾符 | 含義 | 可修飾類型 | 默認規則 |
|---|---|---|---|
signed | 有符號 | char、int | int 默認有符號 |
unsigned | 無符號 | char、int | - |
long | 長型 | int、double | - |
short | 短型 | int | - |
計算機為類型分配固定位寬(如 32 位 int),位模式總數有限(2^32 種),因此可表示值有上下界。超出邊界即發生溢出。關鍵問題:溢出時位模式如何解釋?
unsigned int(以 16 位 unsigned short 為例)2^16 - 1)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 為例)1 00000000000110)1 11111111111001)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

| 表達式 | 二進制(補碼) | 十進制值 | 解釋 |
|---|---|---|---|
a | 0111 1111 1111 1111 | 32767 | 最大正數 |
b = a+1 | 1000 0000 0000 0000 | -32768 | 最小負數(補碼特有) |
c = a+2 | 1000 0000 0000 0001 | -32767 | 補碼:-(2^15 - 1) |
d = a+3 | 1000 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 - 1 | 2^(N-1) - 1 |
| 最小值 | 0 | -2^(N-1) |
| 位模式 0x8000 | 32768 | -32768 |
| 位模式 0xFFFF | 65535 | -1 |
if (a+1 > a) 被優化為 true)unsigned + signed → signed 隱式轉為 unsigned,負數變巨大正數for (unsigned i = n; i >= 0; --i) 永真(i 永不 < 0)gcc -fwrapv 強制有符號環繞語義;-fsanitize=undefined 運行時檢測 UB下一篇將深入剖析 char 類型的符號性、signed char/unsigned char 區別、字符字面量類型、以及更複雜的混合運算陷阱。
本文出自 “趙玉強的博客”,謝絕轉載!