一段看似簡單的代碼,輸出卻令人驚訝:
char a[1000];
for (int i = 0; i < 999; i++)
a[i] = -1 - i;
printf("%d\n", strlen(a)); // 輸出 255,而非 999!
char 範圍:-128 ~ 127(有符號,視編譯器實現)strlen 遇 \0 (值 0) 停止a[0]~a[998]strlen(a) == 255| i | 計算 -1-i | 數學值 | 補碼(8位) | 無符號解讀 | a[i] 實際值 |
|---|---|---|---|---|---|
| 0 | -1-0 | -1 | 11111111 | 255 | -1 |
| 127 | -1-127 | -128 | 10000000 | 128 | -128 |
| 128 | -1-128 | -129 | 1 01111111 → 01111111 | 127 | 127 |
| 129 | -1-129 | -130 | 1 01111110 → 01111110 | 126 | 126 |
| ... | ... | ... | ... | ... | ... |
| 255 | -1-255 | -256 | 1 00000000 → 00000000 | 0 | 0 (\0) |
i = 128:-129 超出 char 下界,高位丟棄,補碼變為 01111111 (127)i = 128~255:值從 127 遞減至 0i = 255:a[255] = 0 → 字符串結束標記a[0]~a[254] 均非 0,strlen 計數 255 後遇 \0 停止-128 ~ 127-129 二進制需 9 位:1 01111111char 只有 8 位,截取低 8 位 01111111 = 127signed char / unsigned char 避免實現相關行為int 計算,結果再截斷存入 char%hhd 打印 char 有符號值,%hhu 打印無符號值歷史原因:早期架構(如 ARM 預設 unsigned、x86 預設 signed)選擇不同,標準委會為了性能不強制統一。現代代碼永不假設 char 符號,需顯式指定。
這個例子生動展示了「類型範圍、補碼環繞、字符串結束符」三大概念的交互碰撞,是 C 語言底層特性的經典教學案例。