[C 的那些眉角] undefined behavior — 那些「在我電腦會動」的陷阱

有一次 review 一個學弟寫的程式碼,他很得意地跟我說:「這段我測過了,跑得好好的。」 我看了一眼,裡面有 … 閱讀全文

[C 的那些眉角]#define vs const vs enum — 定義常數,哪種才對?

在嵌入式開發裡,定義常數這件事做了幾萬次,但我敢說大多數人都沒有認真想過「這三種到底有什麼差別」。

反正 #define 能跑、const 也能用,切換狀態就 enum,好像各有各的場,不去想也沒事。

直到某次 code review,被人問了一句:「這裡為什麼用 #define 而不是 const?」

我愣了一下。說真的,我沒有理由,就只是習慣。


先說結論

不想看完可以直接記這個:

情境 建議
硬體暫存器位址、bit mask #define
有型別的常數值 const
一組互斥的狀態 / 選項 enum
條件編譯、平台切換 #define
陣列長度(C99 以後) enumconst 均可,但 #define 最保險

但只知道結論沒什麼用,知道背後的理由才不會在邊緣情況翻車。

閱讀全文

[C 的那些眉角]型別轉換的隱式陷阱 — 你沒有要轉,但它轉了

有一次我在 review 同事的 code,看到一行:

if (len - sizeof(header) > 0) {

我當下沒說什麼,因為看起來很正常。結果那週 QA 回報說某個封包長度剛好等於 header size 的時候,系統會亂跑。

追進去才發現:lenintsizeof(header)size_t,也就是 unsigned。當 len == sizeof(header) 的時候,相減結果是 0,但如果 len < sizeof(header),你以為是負數,其實是一個很大的正整數。然後 > 0 就是 true。

然後就囧了。

閱讀全文

[C 的那些眉角]巨集函式的副作用 — MAX(a++, b++) 會怎樣

有一次 code review,同事寫了這樣一行:

int result = MAX(sensor_read(), threshold);

我看了一眼沒說什麼,但心裡其實有點毛。

MAX 是怎麼定義的?他說是標準的那種:

#define MAX(a, b) ((a) > (b) ? (a) : (b))

sensor_read() 會被呼叫幾次?他楞了一下。答案是:不一定,可能是一次,也可能是兩次

閱讀全文