1.volatile關鍵字的介紹
volatile關鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,比如:作業系統、硬體或者其他線程等。遇到這個關鍵字聲明的變量,編譯器對通路該變量的代碼就不再進行優化,進而可以提供對特殊位址的穩定通路。
2.volatile關鍵字的用法
當要求使用volatile關鍵字聲明的變量的時候,編譯器總是重新從它所在的記憶體讀取資料,即使它前面的指令剛剛從該處讀取過資料。而且讀取的資料立刻被儲存。
volatile int i = 10;
int a = 0;
int b = 0;
a = i;
//其它代碼并未明确告訴編譯器,對i進行過操作
b = i;
volatile關鍵字指出i是随時可能發生變化的,每次使用它的時候必須從i的位址中讀取,是以編譯器會重新從i的位址讀取資料放在b中。而優化的做法是,由于編譯器發現兩次從i讀資料的代碼之間的代碼沒有對i進行過操作,它會自動把上次讀的資料放在b中。而不是重新從i裡面讀,這樣以來,如果i是一個寄存器變量或者表示一個端口資料就容易出錯,是以說volatile關鍵字可以保證對特殊位址的穩定通路。
一個被volatile關鍵字聲明的變量可能會被意想不到的改變,編譯器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用儲存在寄存器裡的備份。下面是使用到volatile關鍵字的情況:
1)并行裝置的硬體寄存器(如:狀态寄存器)
2)一個中斷服務子程式中會通路到的非自動變量
3)多線程應用中被多個任務共享的變量。
3.volatile關鍵字的舉例說明
1)一個參數即可以是const還可以是volatile嗎?
可以。當它是一個隻讀的狀态寄存器。被volatile關鍵字聲明表示它可能被意想不到地改變。被const關鍵字聲明表示程式不應該去修改它。也就是說,const關鍵字指出我們的程式代碼中是不可以改變這個變量,但是volatile關鍵字指出由于硬體的原因,更改了這個值,但是我們的代碼同時會更新使用這個最新的數值。
2)一個指針變量可以聲明為volatile嗎?
可以。當一個中斷服務子程式修改一個指向一個buffer的指針時。(把指針聲明為volatile類型,可以保證指針所指向的位址随時發生變化)
3)下面所示的代碼是否正确?
int square(volatile int *ptr)
{
return (*ptr * *ptr);
}
錯誤。這段代碼的作用是用來傳回指針*ptr指向值的平方,但是,由于*ptr指向一個volatile類型參數,編譯器産生類似下面的代碼:
int square(volatile int *ptr)
{
int a = 0;
int b = 0;
a = *ptr;
b = *ptr;
return (a * b);
}
由于*ptr的值可能被意想不到的改變,是以a和b可能是不同的。結果,這段代碼可能傳回的不是你期望的平方值。正确代碼如下:
int square(volatile int *ptr)
{
int a = 0;
a = *ptr;
return (a * a);
}