c语言中volatile关键字的作用
讀文章之前 可以先看一下《程序員的自我修養 》第28頁 過度優化。
volatile 提醒編譯器它后面所定義的變量隨時都有可能改變,因此編譯后的程序每次需要存儲或讀取這個變量的時候,都會直接從變量地址中讀取數據。如果沒有 volatile關鍵字,則編譯器可能優化讀取和存儲,可能暫時使用寄存器中的值,如果這個變量由別的程序更新了的話,將出現不一致的現象。下面舉例說明。在DSP開發中,經常需要等待某個事件的觸發,所以經常會寫出這樣的程序:
short flag;
void test()
{
do1();
while(flag==0);
do2();
} 這段程序等待內存變量flag的值變為1(懷疑此處是0,有點疑問,)之后才運行do2()。變量flag的值由別的程序更改,這個程序可能是某個硬件中斷服務程序。例如:如果某個按鈕按下的話,就會對DSP產生中斷,在按鍵中斷程序中修改flag為1,這樣上面的程序就能夠得以繼續運行。但是,編譯器并不知道flag的值會被別的程序修改,因此在它進行優化的時候,可能會把flag的值先讀入某個寄存器,然后等待那個寄存器變為1。如果不幸進行了這樣的優化,那么while循環就變成了死循環,因為寄存器的內容不可能被中斷服務程序修改。為了讓程序每次都讀取真正flag變量的值,就需要定義為如下形式:
volatile short flag;
需要注意的是,沒有volatile也可能能正常運行,但是可能修改了編譯器的優化級別之后就又不能正常運行了。因此經常會出現debug版本正常,但是release版本卻不能正常的問題。所以為了安全起見,只要是等待別的程序修改某個變量的話,就加上volatile關鍵字。
?
? volatile的本意是“易變的”
? 由于訪問寄存器的速度要快過RAM,所以編譯器一般都會作減少存取外部RAM的優化。比如:
static int i=0;
int main(void)
{
?? ...
?? while (1)
?? {
????? if (i) do_something();
?? }
}
/* Interrupt service routine. */
void ISR_2(void)
{
?? i=1;
}
?? 程序的本意是希望ISR_2中斷產生時,在main當中調用do_something函數,但是,由于編譯器判斷在main函數里面沒有修改過i,因此可能只執行一次對從i到某寄存器的讀操作,然后每次if判斷都只使用這個寄存器里面的“i副本”,導致do_something永遠也不會被調用。如果將將變量加上volatile修飾,則編譯器保證對此變量的讀寫操作都不會被優化(肯定執行)。此例中i也應該如此說明。
? 一般說來,volatile用在如下的幾個地方:
? 1、中斷服務程序中修改的供其它程序檢測的變量需要加volatile;
? 2、多任務環境下各任務間共享的標志應該加volatile;
? 3、存儲器映射的硬件寄存器通常也要加volatile說明,因為每次對它的讀寫都可能由不同意義;
? 另外,以上這幾種情況經常還要同時考慮數據的完整性(相互關聯的幾個標志讀了一半被打斷了重寫),在1中可以通過關中斷來實現,2中可以禁止任務調度,3中則只能依靠硬件的良好設計了。
? volatile 的含義
? volatile總是與優化有關,編譯器有一種技術叫做數據流分析,分析程序中的變量在哪里賦值、在哪里使用、在哪里失效,分析結果可以用于常量合并,常量傳播等優化,進一步可以死代碼消除。但有時這些優化不是程序所需要的,這時可以用volatile關鍵字禁止做這些優化,volatile的字面含義是易變的,它有下面的作用:
?1 不會在兩個操作之間把volatile變量緩存在寄存器中。在多任務、中斷、甚至setjmp環境下,變量可能被其他的程序改變,編譯器自己無法知道,volatile就是告訴編譯器這種情況。
2 不做常量合并、常量傳播等優化,所以像下面的代碼:
volatile int i = 1;
if (i > 0) ...
if的條件不會當作無條件真。
? 3 對volatile變量的讀寫不會被優化掉。如果你對一個變量賦值但后面沒用到,編譯器常常可以省略那個賦值操作,然而對Memory Mapped IO的處理是不能這樣優化的。
? 前面有人說volatile可以保證對內存操作的原子性,這種說法不大準確,其一,x86需要LOCK前綴才能在SMP下保證原子性,其二,RISC根本不能對內存直接運算,要保證原子性得用別的方法,如atomic_inc。
? 對于jiffies,它已經聲明為volatile變量,我認為直接用jiffies++就可以了,沒必要用那種復雜的形式,因為那樣也不能保證原子性。
? 你可能不知道在Pentium及后續CPU中,下面兩組指令
inc jiffies
;;
mov jiffies, %eax
inc %eax
mov %eax, jiffies
作用相同,但一條指令反而不如三條指令快。
總結
以上是生活随笔為你收集整理的c语言中volatile关键字的作用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中华经典包括?
- 下一篇: python pdb 基础调试