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