C 語言看似簡單,實則暗藏無數細節陷阱。本文採用「自問自答」模式,精選 10 個高頻核心問題,涵蓋基本類型體系、sizeof 機制、字符編碼、有符號/無符號表示、標準 IO 緩衝、格式化輸出陷阱、運算符優先級記憶法,直擊本質,助你建立精確的 C 語言心智模型。
分類:
char、short、int、long、long long (C99);各有 signed/unsigned 變體。float (單精度)、double (雙精度)、long double (擴展精度)。char、signed char、unsigned char (三種互不相同類型);C11 新增 char16_t, char32_t。_Bool (C99),頭文件 <stdbool.h> 定義 bool、true、false。struct (結構體)、union (共用體)、enum (枚舉)、數組 []。T*、void* (通用指針)、函數指針。void (不可實例化,用於函數返回、指針通用)。| 類型 | LP64 (Linux/macOS) | LLP64 (Windows) | 備註 |
|---|---|---|---|
char | 1 | 1 | 標準保證 |
short | 2 | 2 | |
int | 4 | 4 | 通常 32 位 |
long | 8 | 4 | 跨平台最大差異點 |
long long | 8 | 8 | C99 保證 ≥64 位 |
float | 4 | 4 | IEEE 754 單精度 |
double | 8 | 8 | IEEE 754 雙精度 |
指針 | 8 | 8 | 64 位地址總線 |
結構體對齊陷阱:
struct A { char a; char b; int c; }; // sizeof = 8 (a,b + 2填充 + c)
struct B { char a; char b; char d; int c; }; // sizeof = 8 (a,b,d + 1填充 + c)
struct C { char a; char b; int c; char d; }; // sizeof = 12 (a,b + 2填充 + c + d + 3填充)
規則:成員偏移量必須是其類型大小的整數倍;結構體總大小必須是最大成員大小的整數倍。#pragma pack(n) 可調整對齊係數。
sizeof 是函數還是運算符?運算符 (關鍵字)。編譯期計算類型/表達式佔用字節數,**不求值表達式** (如 sizeof(i++) 不會執行 i++)。語法:sizeof(type) 需括號,sizeof expr 可省略括號。
2^7 = 128;2^8 = 256 (16×16);2^10 = 1024 (KB);2^16 = 65536 (64K)。'0'=48、'A'=65、'a'=97、'\n'=10、'\r'=13、' '=32、DEL=127。signed char vs unsigned char 範圍與記憶法| 類型 | 範圍 | 二進制表示 (8位) | 記憶口訣 |
|---|---|---|---|
signed char | -128 ~ 127 | 最高位符號位,補碼表示 | 無符號 0~255,有符號劈半:-128~127 (正數少一個給 0) |
unsigned char | 0 ~ 255 | 純數值位 | 2^8 - 1 = 255 |
關鍵:char 是否有符號由編譯器決定 (-fsigned-char/-funsigned-char),跨平台代碼**必須顯式指定** signed char 或 unsigned char。
scanf/printf 參數傳值還是傳址?printf("%d", a):傳**值** (讀取變量內容)。scanf("%d", &a):傳**地址** (寫入變量內存)。scanf 需修改變量,必須傳地址;printf 僅讀取,傳值即可。scanf("%d", a) (漏 &) → 未定義行為;格式串空格不匹配 (如 "%d %d" 需輸入空格分隔)。負數補碼規則:-x = ~x + 1 (按位取反加一)。
-1:0xFFFFFFFF (全 1),非 0x80000000。printf("%%d") 輸出字面量 %d (雙百分號轉義)。printf("%c", c) 還有什麼?putchar(c) / fputc(c, stdout)。putchar 通常實現為宏/內聯,開銷更小。注意 char c = 'bc1' 多字符常量實現定義 (通常取低位)。
scanf 不按回車能無限輸入嗎?緩衝區機制揭秘Enter (發送 \n) 後,整行數據連同 \n 一起交付給用戶態 stdin 流緩衝區 (通常 4KB)。scanf 從 stdin 緩衝區讀取;緩衝區空則阻塞等待。fflush(stdin) **C 標準未定義行為** (僅 Windows MSVC 支持清空輸入緩衝區)。跨平台清空輸入緩衝區:int c; while((c=getchar())!='\n' && c!=EOF);。scanf("a=%c", &a); scanf("b=%c", &b); 第二次讀到殘留的 \n。解決:格式串加空格 " %c" 跳過空白符,或用 getchar() 吞噬換行。單目 (++ -- * & ! ~ (type) sizeof) → 算術 (* / % → + -) → 移位 (<< >>) → 關系 (< <= > >=) → 相等 (== !=) → 位與 (&) → 位異或 (^) → 位或 (|) → 邏輯與 (&&) → 邏輯或 (||) → 條件 (?:) → 賦值 (= += -= *= /= %= <<= >>= &= ^= |=) → 逗號 (,)
口訣:「單目最高,算術次之,移位關系邏輯條,賦值最後,逗號最低」。括號 ()、下標 []、成員 . ->、後置 ++ -- 為**後綴運算符**,優先級最高 (結合性左至右)。
C 語言的精髓在於類型系統與內存模型的精確對應。搞清 sizeof 編譯期計算、scanf 地址傳遞、補碼表示、緩衝區行緩衝、運算符優先級結合性,就能規避 90% 的低級 Bug。建議:隨時備查 C99/C11 標準草案 (N1570),養成「不確定就查標準」的習慣。