內(nèi)存訪問速度遠(yuǎn)不及CPU處理速度,所以編譯器優(yōu)化:將內(nèi)存變量緩存到寄存器,但是在某些嵌入式場景中優(yōu)化會出問題:
下面是使用volatile變量的幾個場景:
中斷服務(wù)程序中修改的供其它程序檢測的變量需要加volatile;
例如:
static int i=0;
int main(void)
{
...
while (1){
if (i) dosomething();
}
}
/* Interrupt service routine. */
void ISR_2(void)
{
i=1;
}
程序的本意是希望ISR_2中斷產(chǎn)生時,在main函數(shù)中調(diào)用dosomething函數(shù),但是,由于編譯器判斷在main函數(shù)里面沒有修改過i,因此可能只執(zhí)行一次對從i到某寄存器的讀操作,然后每次if判斷都只使用這個寄存器里面的“i副本”,導(dǎo)致dosomething永遠(yuǎn)也不會被調(diào)用。如果將變量加上volatile修飾,則編譯器保證對此變量的讀寫操作都不會被優(yōu)化(肯定執(zhí)行)。此例中i也應(yīng)該如此說明。
多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)該加volatile
類似上文中中斷服務(wù)程序
存儲器映射的硬件寄存器通常也要加voliate,因?yàn)槊看螌λ淖x寫都可能有不同意義。
例如:
假設(shè)要對一個設(shè)備進(jìn)行初始化,此設(shè)備的某一個寄存器為0xff800000。
int *output = (unsigned int *)0xff800000;//定義一個IO端口;
int init(void)
{
int i;
for(i=0;i< 10;i++){
*output = i;
}
}
經(jīng)過編譯器優(yōu)化后,編譯器認(rèn)為前面循環(huán)半天都是廢話,對最后的結(jié)果毫無影響,因?yàn)樽罱K只是將output這個指針賦值為9,所以編譯器最后給你編譯編譯的代碼結(jié)果相當(dāng)于:
int init(void)
{
*output = 9;
}
如果你對此外部設(shè)備進(jìn)行初始化的過程是必須是像上面代碼一樣順序的對其賦值,顯然優(yōu)化過程并不能達(dá)到目的。反之如果你不是對此端口反復(fù)寫操作,而是反復(fù)讀操作,其結(jié)果是一樣的,編譯器在優(yōu)化后,也許你的代碼對此地址的讀操作只做了一次。然而從代碼角度看是沒有任何問題的。這時候就該使用volatile通知編譯器這個變量是一個不穩(wěn)定的,在遇到此變量時候不要優(yōu)化。
例如:
volatile int *output=(volatile unsigned int *)0xff800000;//定義一個I/O端口