型別修飾詞 const 與 volatile
修飾詞是你附加在型別上、用來加上一個承諾或警告的小字。兩個常見的是 const 與 volatile。const 說「我保證不透過這個名稱去改它」——就像一個寫著「唯讀」的標示。volatile 說「這個值可能在你背後改變,所以每次都要重新讀取」——就像一個編譯器被禁止假設它靜止不動的時鐘面。
const 告訴編譯器:透過這個特定變數,這個值不會被修改,因此任何對它指派的嘗試都是編譯錯誤。這記錄了意圖,也讓編譯器能抓出意外的寫入;它大量用在函式參數上,承諾某函式不會更動你傳入的東西。volatile 較罕見且更底層:它禁止編譯器把讀寫最佳化掉,因為那塊記憶體可能被硬體、被另一個執行緒、或被信號處理常式改動。沒有 volatile,最佳化器可能把值快取在暫存器中,永遠注意不到它變了。關鍵是:volatile 並不是執行緒同步的工具——它不提供原子性或記憶體順序;那要用真正的原子操作或鎖。
為什麼重要:const 關乎安全與清楚的契約——它是你會不斷使用的日常修飾詞,尤其搭配指標來表達資料是唯讀的。volatile 則是給記憶體映射硬體暫存器、以及某些信號處理情境用的專家工具。想用 volatile 來修並行錯誤是個經典錯誤;它既無法消除資料競爭,也無法消除跨執行緒的重排。
const int MAX = 100; /* MAX = 200; 無法編譯 */ volatile int *status_reg = (int *)0x4000; int s = *status_reg; /* 每次都重新讀取;絕不快取 */
const 在編譯期阻止透過 MAX 寫入;volatile 強制每次存取都真正去讀那個硬體暫存器的記憶體。
volatile 不是用來做執行緒同步的——它不提供原子性也不提供記憶體順序。共享狀態請用 C11 原子操作或互斥鎖。const 是編譯期的承諾,不是強制的記憶體保護;把它強制轉掉再寫入是未定義行為。