整數表示 (Integer Representations)

Overview Table

主題 核心觀念 關鍵公式 / 事實 書頁
整數資料型別 (Integral Data Types) C 的整數型別範圍非對稱;long 隨 32/64-bit 程式而異 負數範圍比正數多 1 p.96-98
無號編碼 (Unsigned Encoding) 每個 bit 權重 2i,B2U 是雙射 (bijection) B2Uw(x)=i=0w1xi2i p.98-100
二補數編碼 (Two's-Complement) 最高位權重為 2w1(sign bit),B2T 是雙射 B2Tw(x)=xw12w1+i=0w2xi2i p.100-103
重要常數 UMax、TMin、TMax 之間的固定關係 UMax=2TMax+1;|TMin|=|TMax|+1 p.102
有號⇄無號轉換 cast 時位元樣式不變,數值解讀改變 T2Uw(x)=x+xw12w;U2Tw(u)=uuw12w p.106-110
C 的 signed/unsigned 混合運算時 signed 隱式轉為 unsigned -1 < 0U 為假(false) p.110-112
位元擴展 (Expanding) 無號:zero extension;二補數:sign extension 兩者皆保值 p.112-116
截斷 (Truncating) 丟棄高位 → 相當於 mod 2k,是一種 overflow x=xmod2k(unsigned) p.117-118
使用建議 隱式轉換是 bug 溫床;多數語言不提供 unsigned Java 只有 signed + >>> p.119-120
記號約定 (p.95-96, Figure 2.8)

下標 w 表位元寬度。B2U/B2T = binary→unsigned / two's complement;U2B/T2B 為其反函數;T2U/U2T 為兩種數值解讀間的轉換;UMax/TMin/TMax 為三個特殊常數。


2.2.1 整數資料型別 (Integral Data Types) (p.96-98)

C 提供 charshortintlong 等大小指定,搭配 unsigned(全為非負)或預設有號 (signed)。實際位元組數依 32-bit 或 64-bit 程式而定,其中唯一機器相依的是 long:32-bit 程式用 4 bytes,64-bit 程式用 8 bytes。

型別 (64-bit 程式典型值) 最小 最大
[signed] char −128 127
unsigned char 0 255
short −32,768 32,767
int / int32_t −2,147,483,648 2,147,483,647
unsigned / uint32_t 0 4,294,967,295
long / int64_t −9,223,372,036,854,775,808 9,223,372,036,854,775,807
unsigned long / uint64_t 0 18,446,744,073,709,551,615
可攜性例外

C 標準不要求有號數用二補數表示,也不保證 long 的確切範圍;追求極致可攜的程式只能假設 Figure 2.11 的最小範圍。但幾乎所有現代機器都用二補數,大量程式依此假設仍可廣泛移植 (p.103)。

2.2.2 無號編碼 (Unsigned Encodings) (p.98-100)

把位元向量 x=[xw1,xw2,,x0] 直接視為二進位數,每個為 1 的 bit i 貢獻 2i:

B2Uw(x)i=0w1xi2i(2.1)

2.2.3 二補數編碼 (Two's-Complement Encodings) (p.100-106)

最常見的有號數表示。定義:最高有效位 (most significant bit) xw1 稱 sign bit,權重為 2w1(無號時該位權重的相反數);其餘位權重不變:

B2Tw(x)xw12w1+i=0w2xi2i(2.3)
常數 w=8 w=16 w=32 w=64
UMaxw 0xFF (255) 0xFFFF (65,535) 0xFFFFFFFF (4,294,967,295) 0xFFFF...F (≈1.8×10¹⁹)
TMinw 0x80 (−128) 0x8000 (−32,768) 0x80000000 (−2,147,483,648) 0x8000...0
TMaxw 0x7F (127) 0x7FFF (32,767) 0x7FFFFFFF (2,147,483,647) 0x7FFF...F
−1 0xFF 0xFFFF 0xFFFFFFFF 0xFFFF...F
替代表示法 (Aside, p.104)

  • 反碼 (Ones' complement):sign bit 權重為 (2w11),即 B2Ow(x)xw1(2w11)+i=0w2xi2i
  • 符號-大小 (Sign magnitude):B2Sw(x)(1)xw1i=0w2xi2i
  • 兩者都有 +0 與 −0 兩種零編碼(sign-magnitude 的 −0 是 [10...0];ones' complement 的 −0 是 [11...1]),現代機器幾乎不用;sign magnitude 用於浮點數,見 02-Information-Representation/04-Floating-Point
  • 名稱由來:two's complement 因 x=2wx(一個 2);ones' complement 因 x=[111]x(多個 1)。

2.2.4 有號與無號間的轉換 (Conversions between Signed and Unsigned) (p.106-110)

C 的 cast(如 (unsigned) x(int) u)在多數實作採位元層觀點而非數值觀點:保持位元樣式不變,只改變解讀方式。例:(unsigned short)(-12345) 得 53,191(同為 0xCFC7);(int) 4294967295u 得 −1(同為 0xFFFFFFFF)。

定義 T2Uw(x)B2Uw(T2Bw(x))U2Tw(u)B2Tw(U2Bw(u))。由式 (2.1)(2.3) 相減可得 B2Uw(x)B2Tw(x)=xw12w,故:

T2Uw(x)=x+xw12w={x+2w,x<0x,x0(2.5,2.6)U2Tw(u)=uw12w+u={u,uTMaxwu2w,u>TMaxw(2.7,2.8)
T2U:二補數 → 無號 (Figure 2.17)      U2T:無號 → 二補數 (Figure 2.18)

 二補數                無號              無號                 二補數
 TMax ──不變──▶ TMax                  UMax ──−2^w──▶ −1
   0  ──不變──▶ 0                    2^w−1 │ (>TMax 的大數變負)
  −1  ──+2^w──▶ UMax                TMax+1 ──−2^w──▶ TMin
 TMin ──+2^w──▶ TMax+1 = 2^(w−1)      TMax ──不變──▶ TMax
 (負數變大正數)                          0  ──不變──▶ 0

2.2.5 C 語言中的 Signed vs. Unsigned (p.110-112)

常數預設為 signed(如 123450x1A2B);加後綴 U/u 成為 unsigned(如 12345U)。轉換可經顯式 cast隱式賦值(tx = ux;)發生,兩者效果相同(套用 U2T / T2U)。

運算式 實際比較型別 結果 說明
0 == 0U unsigned 1
-1 < 0 signed 1
-1 < 0U unsigned 0 −1 → 4294967295U
2147483647 > -2147483647-1 signed 1 TMax > TMin
2147483647U > -2147483647-1 unsigned 0 TMin → 2³¹ = TMax+1
2147483647 > (int) 2147483648U signed 1 2³¹ → TMin
-1 > -2 signed 1
(unsigned) -1 > -2 unsigned 1 兩邊皆轉無號,UMax > UMax−1
為何 TMin 要寫成 -2147483647-1?(Web Aside DATA:TMIN, p.113)

-2147483648 在 C 中是「對常數 2147483648 取負」,而 2147483648 已超出 int 正數範圍——二補數不對稱性與 C 轉換規則的交互作用使其型別解讀出現詭異行為。因此 limits.h 定義 #define INT_MIN (-INT_MAX - 1)

2.2.6 位元擴展 (Expanding the Bit Representation) (p.112-116)

小型別 → 大型別的轉換恆可保值,規則依原型別而定:

sign extension 保值示意 (w=3 → w=4, Figure 2.20):
[101]  = -4 + 1           = -3
[1101] = -8 + 4 + 1       = -3   (新 sign bit 的 -8 與轉正的 +4 合成 -4)
[111]  = -4 + 2 + 1       = -1
[1111] = -8 + 4 + 2 + 1   = -1
大小與型別轉換的順序 (p.116)

short sx = -12345; unsigned uy = sx; 結果是 4,294,954,951(0xFFFFCFC7)而非 53,191。C 標準規定先改變大小、再改變型別:(unsigned) sx(unsigned)(int) sx(先 sign extend 再重新解讀),而非 (unsigned)(unsigned short) sx

2.2.7 截斷 (Truncating Numbers) (p.117-118)

將 w-bit 數截斷為 k-bit:直接丟棄高位的 w−k 個 bit,保留 x=[xk1,,x0]。截斷可能改變數值——是一種 overflow

擴展 vs. 截斷 資料流:
              zero ext (unsigned):前補 0
  w-bit ────────────────────────────────▶ w'-bit  (w' > w, 保值)
              sign ext (2's comp):前補 sign bit

              truncate:丟棄高位 w−k bits
  w-bit ────────────────────────────────▶ k-bit   (可能 overflow: mod 2^k)

2.2.8 Signed vs. Unsigned 的使用建議 (p.119-120)

隱式 signed→unsigned 轉換在程式碼中毫無視覺線索,是難以察覺的 bug 來源。經典錯誤模式(源自 Practice Problems 2.25、2.26):

移位相關備註(本頁範圍起頭的 Asides, p.95)

  • 移位量 kw:C 標準未定義行為;許多機器實際只取移位量的低 log2w 位(即位移 kmodw),但不可依賴——移位量應保持小於 word size。Java 則明文規定取模。
  • 運算子優先權:1<<2 + 3<<4 等於 (1 << (2+3)) << 4 = 512,而非直覺的 (1<<2)+(3<<4) = 52——加減法優先權高於移位。不確定就加括號。


Exam/Test Patterns

情境 / 關鍵字 答案
給 hex/bit pattern 求無號值 B2Uw=xi2i(每個 1-bit 加 2i)
給 hex/bit pattern 求二補數值 B2Tw:最高位算 2w1,其餘同無號(如 0xA=[1010] → 8+2=6)
判斷 disassembler 中 32-bit hex 常數正負 (Prob 2.18) 最高 hex digit 為 8~F(最高 bit=1)→ 負;值 = 無號值 − 232
求 w-bit 的 UMax / TMin / TMax 2w1 / 2w1 / 2w11;hex:全 F / 8 後全 0 / 7 後全 F
為何負數範圍比正數多一個? 二補數不對稱:sign bit=1 全為負;sign bit=0 那半包含 0
負數 x cast 成 unsigned 的值 x+2w(位元不變);T2U(−1)=UMax、T2U(TMin)=TMax+1
大無號數 u cast 成 int u2w(當 u>TMaxw);U2T₃₂(231) = TMin₃₂
signed 與 unsigned 混合比較 signed 隱式轉 unsigned 再比;-1 < 0U → 0 (false)
unsigned length、迴圈 i <= length-1、length=0 0−1 wrap 成 UMax,條件永真 → 記憶體錯誤
兩個 size_t(無號)相減判大小 差永為非負,判斷失效;改用 > 直接比較
short → int(有號)擴展 sign extension:前補 sign bit 複本,值不變
unsigned short → unsigned 擴展 zero extension:前補 0,值不變
short 負數直接 cast 成 unsigned(同時改大小與型別) 先改大小(sign extend)再改型別:得 x+232 而非 x+216
int → short 截斷後的值 xmod216,若結果 > TMax₁₆ 再減 216
(word << 24) >> 24 對 unsigned vs int 的差別 (Prob 2.23) unsigned 邏輯右移(高位補 0);int 算術右移(sign extend)→ 後者可做低 byte 的符號擴展
為何 INT_MIN 定義為 (-INT_MAX - 1) 常數 2147483648 超出 int 正範圍,直接寫 -2147483648 型別解讀有陷阱
1<<2 + 3<<4 的值 512(加法優先權高於移位,結合為 (1<<5)<<4)
移位量 ≥ w 的行為 C 未定義;許多機器取 kmodw,不可依賴
反碼 / 符號-大小表示的共同特徵 都有 +0 與 −0 兩種零編碼