為什麼工程師要看股票? 不是要當股神,是要對自己負責

記得剛出社會沒多久,有一件事讓我覺得很奇怪。

公司裡的工程師們,不管資歷深淺,午休時間幾乎人手一個看盤 App,偶爾三三兩兩討論一下某支股票。我那時候心想,大家不是來寫程式的嗎?幹嘛盯著那個。

後來有個前輩點醒了我:「你以後會需要懂一點股票,不是要靠它發財,是為了讓自己在職涯裡做出更好的決定。」

當時聽完覺得有點玄,現在回頭看,還真的是這樣。


看懂公司,才知道你在哪條船上

科技業的工作環境有個特性:公司的命運跟你的命運是綁在一起的。

閱讀全文

[C 的那些眉角]Bit 操作的乾淨寫法 — 告別 magic number

嵌入式開發幾乎離不開 bit 操作。

設定硬體暫存器、解析通訊協定封包、
控制 GPIO、讀取狀態旗標,
到處都是對特定 bit 的讀寫。

我剛開始寫嵌入式的時候,
程式碼長這樣:

// 設定 UART 控制暫存器
UART_CTRL |= 0x01; // 啟用 TX
UART_CTRL |= 0x02; // 啟用 RX
UART_CTRL &= ~0x04; // 關閉 loopback
UART_CTRL |= (0x03 << 4); // 設定 baud rate 為 115200

當下寫的時候覺得沒問題,
因為我知道每個數字代表什麼。

三個月後回來看,
完全不知道 0x010x020x04 是什麼意思,
要翻 datasheet 才能看懂。

這就是 magic number 的問題。

閱讀全文

[C 的那些眉角]volatile 到底是什麼 — 我花了很久才搞懂

volatile 是我學 C 語言以來,
花最久時間才真正搞懂的關鍵字。

不是因為語法複雜,
而是因為它的效果是「阻止編譯器做某些優化」,
在沒有優化的情況下,
加不加 volatile 看起來沒有差別,
讓人誤以為自己懂了。

直到有一天,開啟了 -O2 優化,
程式行為突然變了,
才發現原來自己一直用錯。

閱讀全文

[C 的那些眉角] switch 記得加 default — 防禦未來的自己

有一種 bug,不是今天的你造成的,
是三個月後的你造成的。

你現在寫了一個 switch
處理三種狀態,邏輯完全正確,
測試也都過了。

三個月後,需求改了,
新增了第四種狀態。
你在 enum 裡加了一個值,
但忘記去更新那個 switch

編譯過了,沒有警告,
程式跑起來,遇到第四種狀態的時候,
switch 什麼都不做,
靜靜地繼續往下執行。

症狀可能是某個功能沒有反應,
可能是某個變數沒有被更新,
可能要跑很久才會觸發那個狀態,
然後你花了半天才找到原因。

default 加一行,可以讓這種問題立刻現形。

閱讀全文

[C 的那些眉角]整數溢位比你想的更常見

有一個 bug,我在 code review 的時候無意間看到,
當下覺得「這不會有問題吧」,
但仔細算了一下,發現真的會出問題。

uint16_t a = 60000;
uint16_t b = 10000;
uint16_t sum = a + b; // 你覺得 sum 是多少?

答案不是 70000。

uint16_t 最大值是 65535,
70000 超過了,發生溢位,
sum 實際上是 70000 - 65536 = 4464

程式繼續跑,用著這個錯誤的值,
後續的計算全部都錯了,
但不會 crash,不會有任何警告。

這就是整數溢位的恐怖之處。

閱讀全文

[C 的那些眉角]陣列邊界檢查 — 緩衝區溢位的根源

緩衝區溢位(Buffer Overflow)是 C 語言最惡名昭彰的問題之一。

它不只是會讓程式 crash,
在某些情況下,它是駭客攻擊的入口。
歷史上很多嚴重的安全漏洞,
根源都是一個沒有做邊界檢查的陣列存取。

但在嵌入式開發,我更常遇到的不是安全問題,
而是「程式跑著跑著,某個全域變數的值莫名其妙被改掉」,
或是「UART 收到一個比預期長的封包,程式就 crash 了」。

追到最後,都是同一件事:
有人寫到了陣列邊界以外的地方。

閱讀全文

[C 的那些眉角]assert 是你的好朋友 — 但要用對地方

有一種 bug,你看了半天程式碼,
覺得「這裡不可能出問題」,
但它就是出問題了。

然後你加了一堆 printf
把每個變數的值都印出來,
才發現某個「不可能是 NULL」的指標,
在某個罕見的情況下真的是 NULL。

如果當初在那裡加了 assert
程式會在第一時間告訴你問題在哪,
而不是讓錯誤默默蔓延,
最後在完全不相關的地方 crash。

assert 就是做這件事的。

閱讀全文

[C 的那些眉角]Stack Overflow — 嵌入式的堆疊管理

一聽到 Stack Overflow 這個名字,
大部分工程師第一個想到的是那個問答網站。

但在嵌入式開發,Stack Overflow 是一個真實會發生的災難,
而且症狀往往讓你完全摸不著頭緒。

程式跑著跑著突然 reset,
某個全域變數的值莫名其妙被改掉,
函式回傳之後跳到奇怪的位址,
或是程式直接進入 HardFault Handler,
然後你盯著 register dump 發愁。

這些症狀背後,很多時候都是同一個原因:
Stack 被寫爆了。

閱讀全文

[C 的那些眉角]malloc 之後一定要檢查 — 記憶體配置的防禦性寫法

平常在嵌入式系統上用 malloc
寫完之後覺得很爽,動態配置記憶體,好像很厲害。

uint8_t *buf = malloc(1024);
memset(buf, 0, 1024);
// 開始用 buf...

有一次朋友看了一眼問我:「malloc 失敗怎麼辦?」

我說:「會失敗嗎?記憶體應該夠吧?」

他說:「嵌入式的 heap 就那麼大,你確定嗎?」

我 ........ 當然不是很確定。

閱讀全文

[C 的那些眉角]指標用完要歸零 — 懸空指標的恐怖故事

有一種 bug,我只要想到就頭皮發麻。

明明程式跑得好好的,突然在某個完全不相關的地方 crash,
或是資料莫名其妙被改掉,
或是在開發機上完全正常,到了產品上偶爾出問題。

很多時候,追到最後都是同一個兇手:

懸空指標(Dangling Pointer)。

閱讀全文