許多初學者疑惑:`signed char` 為 8 位元,為何範圍不是 -127~127,而是 -128~127?關鍵在於電腦採用 二補數 表示有號整數。本文從原碼、反碼、補碼定義推導,並附贈兩道經典面試題。
| 補碼 (二進位) | 對應原碼 | 十進位值 | 實際表示 |
|---|---|---|---|
| 0000 0000 | 0000 0000 | 0 | 0 |
| ... | ... | ... | ... |
| 0111 1111 | 0111 1111 | 127 | +127 |
| 1000 0000 | 1000 0000 | 128 | -128 |
| ... | ... | ... | ... |
| 1111 1111 | 0000 0001 | 1 | -1 |
關鍵點:1000 0000 在補碼系統中無對應的正數原碼(正數最大 0111 1111 = 127),電腦直接將其視為 -128。這是因為補碼編碼下,負數範圍比正數多一個,且 最高位權值為 -128(而非 -0)。
驗證:1000 0000 = -128 + 0 = -128;1111 1111 = -128 + 64+32+16+8+4+2+1 = -1。
int main() {
char a[1000];
for (int i = 0; i < 1000; i++) a[i] = -1 - i;
printf("%d\n", strlen(a));
return 0;
}
解析:`char` 預設有號(實作定義),`-1 - i` 依補碼截取低 8 位。`strlen` 尋找第一個 `\0` (0x00)。
`i=0` → -1 (0xFF) … `i=254` → -255 (0x01) → `i=255` → -256 (0x00)。
第 256 個元素 (索引 255) 為 0,`strlen` 回傳 255。
答案:255
void foo() {
unsigned int a = 6;
int b = -20;
(a + b) > 6 ? puts(">6") : puts("<=6");
printf("%u\n", a + b);
}
解析:`a+b` 含無號數,`b` 隱式轉為 `unsigned int` (4294967276)。
`6 + 4294967276 = 4294967282` (模 2^32),大於 6 → 輸出 `>6`。
`printf("%u")` 印出 4294967282。
答案:>6
理解補碼編碼機制,即可釐清有號整數範圍非對稱的本質:最高位權值為負,導致負數多一個表示值。實務上需警惕有號/無號混合運算導致的隱式轉換陷阱。