volatile 告訴編譯器:「這個變數可能在編譯器無法感知的情況下被修改,請每次存取都直接讀寫記憶體,不要優化成暫存器快取。」
| 場景 | 範例 | 說明 |
|---|---|---|
| 硬體暫存器映射 | volatile uint32_t *GPIO = (uint32_t*)0x40020000; | 每次讀寫對應真實總線操作,不可合併或消除 |
| 中斷服務程式共享旗標 | volatile int flag = 0; | ISR 修改,主迴圈輪詢;無 volatile 會被優化成死迴圈 |
| 多執行緒共享變數 | volatile int signal = 0; | 編譯器不知其他執行緒會改值,需強制重讀 |
| setjmp/longjmp 環境 | volatile int saved_state; | 跨跳轉存取的變數不可暫存器化 |
/* 錯誤:編譯器可能將 flag 載入暫存器,while 變無限迴圈 */
int flag = 0;
void wait_flag(void) {
while (flag == 0); // 若 flag 在暫存器,ISR 修改記憶體無效
}
/* 正確 */
volatile int flag = 0;
void wait_flag(void) {
while (flag == 0); // 每次迴圈皆從記憶體讀取
}
volatile int i; i++; 仍非原子,需 atomic_inc 或鎖。__sync_synchronize()、memory_barrier() 或 C11 atomic_thread_fence。資料流分析會進行「常數傳播」、「死碼消除」、「暫存器分配」。volatile 變數會被標記為「可能有副作用」,阻擋上述優化:
if (v > 0) 不會被視為恆真)。atomic_*、鎖、記憶體屏障解決同步問題,volatile 僅解決「可見性」。volatile。