volatile 告訴編譯器:「這個變數的值可能在程式不可控的情況下發生變化,請不要優化對它的存取,每次都要直接從記憶體讀寫。」它常用於硬體暖存器、共享記憶體、中斷服務程式(ISR)修改的變數、多執行緒共享旗標等場景。
可以。 典型例子是唯讀狀態暖存器。它是 volatile,因為硬體可能隨時更新其值;它是 const,因為程式碼不應嘗試修改它。
const volatile uint32_t *STATUS_REG;
可以。 當中斷服務程式修改一個指向緩衝區的指標時,該指標變數本身需宣告為 volatile。
char * volatile buffer_ptr; // 指標值可能被 ISR 修改
為了速度,編譯器常將變數值載入暫存器,後續讀取直接用暫存器值。但若變數在「本執行緒之外」被修改(如硬體、其他執行緒、ISR),暫存器值不會同步更新,導致程式讀到舊值。
網路上常見「易變的」翻譯容易誤導。本質上,volatile 強制編譯器產生直接對記憶體位址進行讀寫的機器碼,繞過暫存器快取,確保數據一致性。
int square(volatile int *ptr) {
return *ptr * *ptr; // 危險!
}
編譯器可能展開為:
int a = *ptr; // 第一次讀取
int b = *ptr; // 第二次讀取,若 ptr 指向硬體計數器,值可能已變!
return a * b; // 回傳的不再是平方數
long square(volatile int *ptr) {
int a = *ptr; // 只讀取一次存入區域變數
return a * a;
}
volatile 只保證可見性,不保證原子性或順序性,仍需 mutex/atomic 搭配。volatile 是嵌入式與系統級開發的利器,核心在於「阻止編譯器對特定記憶體位置的存取優化」。理解其底層機制(暫存器 vs 記憶體),並避開「多次讀取 volatile 物件」等陷阱,才能寫出正確、健壯的底層代碼。