在 C 語言網路程式開發中,常遇到一個困惑:明明變數值為 0xc9,用 printf("%x", c) 輸出卻變成 ffffffc9。本文從記憶體表示、型別提升、補碼機制三個維度徹底解析這一現象,並提供兩種標準修正方案。
#include <stdio.h>
int main() {
char c = 0xc9; // 有號 char,最高位 1 視為負數
printf("A: c = %2x\n", (unsigned char)c); // 強制轉無號
printf("B: c = %2x\n", c & 0xff); // 位元遮罩
printf("C: c = %2x\n", c); // 直接輸出(問題重現)
return 0;
}
輸出結果:
A: c = c9 B: c = c9 C: c = ffffffc9
unsigned int根據 C 標準,可變參函數會觸發預設引數提升:char/short 自動提升為 int。此處 char c 被提升為 int 傳給 printf。
char c = 0xc9(二進位 1100 1001),最高位為 1,視為負數(-55)。提升為 32 位 int 時,進行符號擴展:高 24 位全部填 1。
char (8 bit) : 1100 1001 (0xC9) int (32 bit): 1111 1111 1111 1111 1111 1111 1100 1001 (0xFFFFFFC9)
1 0110111(-55)1 10010001 1001001(即 0xC9)擴展為 int 後,補碼高位全 1,故輸出 ffffffc9。
| 方案 | 代碼 | 原理 | 推薦度 |
|---|---|---|---|
| A:強制轉型 | (unsigned char)c |
先轉為 unsigned char(0xC9 視為 201),再提升為 int,高位補 0 |
⭐⭐⭐⭐⭐ 最規範、語意清晰 |
| B:位元遮罩 | c & 0xff |
與 0xFF 做 & 運算,保留低 8 位,高位清零 | ⭐⭐⭐⭐ Linux 核心常用,效能略高 |
unsigned char (8 bit): 1100 1001 (0xC9,無符號,值 201) int (32 bit) : 0000 0000 0000 0000 0000 0000 1100 1001 (0x000000C9)
無符號型別提升時進行零擴展,高位補 0,輸出正確。
printf("%02x", (unsigned char)c),語意明確,可移植性最好。uint8_t(unsigned char),從源頭避免有號問題。%02x 保證兩位數對齊,如 0a 而非 a。0xffffff 前綴並非錯誤,而是有號 char 符號擴展的必然結果。理解「整型提升 → 符號/零擴展 → printf 解讀」這一鏈路,即可從根源上避免此類坑。