volatile 是一種類型修飾符,用於聲明的變量表示其值可能被編譯器未知的因素修改,例如:作業系統、硬體裝置、其他執行緒等。當編譯器遇到被 volatile 修飾的變量時,會放棄對該變量訪問代碼的優化,確保每次讀寫都直接操作記憶體位址,從而提供對特殊位址的穩定訪問。
int volatile nVint;
當程式需要讀取 volatile 變量的值時,系統總是重新從其所在的記憶體讀取數據,即使前一條指令剛從該處讀取過。讀取的數據會立即被保存,不會被暫存於暫存器中。
考慮以下代碼片段:
volatile int i = 10;
int a = i;
// ... 其他代碼,未對 i 進行明確操作
int b = i;
無 volatile 時: 編譯器發現兩次讀取 i 之間沒有對 i 的操作,會優化為直接使用上次讀取的值賦給 b,而不重新從記憶體讀取。若 i 對應硬體暫存器或埠資料,這會導致錯誤。
有 volatile 時: 編譯器生成的組合語言會強制重新從 i 的位址讀取數據存入 b,保證訪問的即時性。
在 VC6 中,Debug 模式預設不優化,故 volatile 效果不明顯。下面通過內嵌組合語言修改記憶體中 i 的值(編譯器不知情),對比有無 volatile 的行為。
#include <stdio.h>
void main() {
int i = 10;
int a = i;
printf("i = %d\n", a);
// 內嵌組合語言修改 i 的記憶體值,編譯器不知情
__asm {
mov dword ptr [ebp-4], 20h
}
int b = i;
printf("i = %d\n", b);
}
#include <stdio.h>
void main() {
volatile int i = 10; // 加上 volatile
int a = i;
printf("i = %d\n", a);
__asm {
mov dword ptr [ebp-4], 20h
}
int b = i;
printf("i = %d\n", b);
}
實驗證明 volatile 成功阻止了編譯器的優化,確保每次訪問都從記憶體重新讀取,對硬體編程、多執行緒共享變量至關重要。