首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言奇技淫巧 25 期:stdout/stderr 緩衝、printf 返回值、switch 作用域、sizeof 不求值、數組下標交換、類型懲罰

     編輯:關於C語言

Q1:stdout 輸出順序亂了?—— 行緩衝 vs 無緩衝


while (1) {
    fprintf(stdout, "stdout.");  // 行緩衝:遇 \n 或滿才刷新
    fprintf(stderr, "stderr.");  // 無緩衝:立即輸出
    sleep(1);
}
// 輸出:stderr.stderr.stderr.... (好久才出現 stdout.)

修正:setbuf(stdout, NULL); 將 stdout 設為無緩衝,或每次 fflush(stdout); 手動刷新。

原理:終端關聯時 stdout 默認行緩衝,stderr 默認無緩衝(保證錯誤信息即時可見)。重定向到文件時 stdout 變全緩衝,更明顯。

Q2:printf 返回值不是字符數?—— UTF-8 多字節陷阱


char* str = "我";  // UTF-8 編碼佔 3 字節
printf("%d\n", printf(str));  // 輸出 3,而非 1

鐵律:printf 返回實際輸出的字節數,而非字符數、碼位數。UTF-8 下中文字符佔 3 字節,返回 3 完全正確。

Q3:switch 大括號內聲明變量不初始化?


switch (a) {
    int b = 2;      // 永遠不會執行!
    case 1: printf("%d", b); break;
}

標準規定:case/default 標籤前的代碼**永遠不會執行**(編譯器直接生成跳轉指令)。b 未初始化,讀取行為未定義。

對策:嚴禁在 switch 塊頂層聲明帶初始化的變量,需放入 case 內部或用 {} 包裹成複合語句。

Q4:sizeof(i++) 不會讓 i 自增?


int i = 1;
printf("%zu\n", sizeof(i++));  // 輸出 4 (int 大小)
printf("%d\n", i);             // 輸出 1,i 未增!

核心規則:sizeof 是**編譯期運算符**(除非常數長度數組),僅根據表達式**類型**計算大小,**不求值**表達式。i++ 只提供類型信息 int,副作用被丟棄。

Q5:2["hello"] 等於 "hello"[2] ?


char ch = 2["hello"];  // ch == 'l'

原理:a[b] 由編譯器統一翻譯為 *(a + b)。
2["hello"] → *(2 + "hello") → *("hello" + 2) → "hello"[2]。
本質:指針算術 ptr + index 與加法交換律,index[ptr] 只是冷門寫法。

Q6:int 用 %f 輸出會怎樣?—— 類型懲罰


int d = 2;
printf("%f\n", d);  // 輸出垃圾值如 0.000000 或隨機浮點數

原因:printf 根據 %f 從棧上讀取 sizeof(double) (8字節) 數據並按 IEEE 754 解釋。實際傳入 int (4字節),高 4 字節為棧上殘留垃圾,組合成無意義浮點數。
嚴重後果:棧對齊差異、調用約定差異可能導致後續參數全亂,屬**未定義行為**。

IEEE 754 單精度浮點數位佈局驗證


typedef union {
    float f;
    struct { unsigned int dot:23; unsigned int exp:8; unsigned int sign:1; } bits;
} float_value;

float_value fv;
fv.bits.sign = 1;      // 負數
fv.bits.exp  = 128;    // 指數偏移 127 → 實際指數 1
fv.bits.dot  = 0;      // 尾數 1.0
printf("%f\n", fv.f);  // 輸出 -2.000000

總結:C 語言「看似莫名,實則有章」

現象底層機制避坑口訣
輸出順序亂stdout 行緩衝 vs stderr 無緩衝交互輸出加 fflush 或 setbuf(NULL)
printf 返回字節數格式化輸出實際寫入字節計數字符數≠字節數,UTF-8 中文 3 字節
switch 變量未初始化case 標籤即跳轉地址,前置代碼不可達switch 頂層不聲明帶初始化變量
sizeof 不求值編譯期按類型計算大小sizeof 內不寫副作用表達式
數組下標可交換a[b] ≡ *(a+b) ≡ b[a]冷知識,代碼中別這樣寫
格式化字符串類型不匹配變參無類型檢查,按格式字符串盲目讀棧開啟 -Wformat 警告,嚴格匹配
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved