C 語言看似簡單,實則暗藏許多「未定義行為」「實作定義行為」與「標準細節」。以下 14 道經典謎題涵蓋 I/O 緩衝、逗號運算子、printf 回傳值、浮點數記憶體佈局、extern 型別不匹配、switch 作用域、緩衝區溢位、sizeof 不求值特性、八進位常數、註解陷阱、短路求值、陣列下標交換、scanf 格式字串、運算子優先級等核心知識點。
while(1) {
fprintf(stdout, "hello-std-out");
fprintf(stderr, "hello-std-err");
sleep(1);
}
現象:stderr 立即顯示,stdout 延遲。
原因:stdout 預設全緩衝(遇換行/滿/flush 才輸出),stderr 無緩衝。
int a = 1,2; // 編譯錯誤
int a = (1,2); // 正確,a=2
宣告中逗號是分隔符,非運算子;需加括號構成逗號運算式。
printf("%d\n", printf("%d", printf("%d", 43))); // 輸出 4321
內層印 43 回傳 2,中層印 2 回傳 1,外層印 1。
float a = 12.5f;
printf("%d\n", a); // 0 (float 推升為 double,前 4 bytes 為 0)
printf("%d\n", (int)a); // 12
printf("%d\n", *(int*)&a); // 1095237632 (IEEE 754 位元模式)
// file1.c: int arr[80];
// file2.c: extern int *arr; // 型別不符,運行時崩潰
// 正確:extern int arr[];
switch(a) {
int b = 20; // 被跳過,b 未初始化
case 1: printf("%d", b);
}
char str[80];
scanf("%s", str); // 輸入超過 79 字元 → UB
int i=10;
sizeof(i++); // 不執行 i++,i 仍為 10
int pot[] = {0001, 0010, 0100, 1000}; // 1, 8, 64, 1000
y = y/*p; // /* 開啟註解,p 後內容被忽略
int i=6;
if ( ((++i<7) && (i++/6)) || (++i<=9) );
// 逐步推演得 i=8
"hello"[2] == 2["hello"] // 皆為 'l'
因 a[b] ≡ *(a+b) ≡ *(b+a) ≡ b[a]。
scanf("%[^r]", buf); // 讀到 'r' 停止
// 輸入 "Hello, World" → 讀取 "Hello, Wo"
t = a<<2 + a; // 實為 a << (2+a)
t = (a<<2) + a; // 正確:乘 5
這些謎題揭示了 C 語言「看似直覺實則陷阱」的特性。建議開發者:
-Wall -Wextra -pedantic)。