C語言關鍵字之volatile

2021-08-17 08:14:32 字數 1624 閱讀 5666

volatile 總是與優化有關,編譯器有一種技術叫做資料流分析,分析程式中的變數在**賦值、在**使用、在**失效,分析結果可以用於常量合併,常量傳播等優化,進一步可以消除一些**。但有時這些優化不是程式所需要的,這時可以用 volatile 關鍵字禁止做這些優化。

int flag = 0;

int main( void )

}void interrupt_isr( void )

程式的本意是希望 interrupt_isr 中斷產生時,在 main 當中呼叫 do_something 函式,但是由於編譯器判斷在main函式裡面沒有修改過 flag,因此可能只執行一次對從 flag 到某暫存器的寫操作,然後每次 if 判斷都只使用這個暫存器裡面的「flag 副本」,導致 do_something 永遠也不會被呼叫。如果變數加上 volatile 修飾,則編譯器保證對此變數的讀寫操作都不會被優化(肯定執行)。這個例子中 flag 應該宣告為 volatile int flag = 0;

需要注意的是,沒有 volatile 也可能能正常執行,但是可能修改了編譯器的優化級別之後就又不能正常執行了。因此經常會出現 debug 版本正常,但是 release 版本卻不能正常的問題。所以為了安全起見,只要是等待別的程式修改某個變數的話,就加上 volatile 關鍵字。

一般說來,volatile 用在如下的幾個地方:

1. 中斷服務程式中修改的供其它程式檢測的變數需要加 volatile;

2. 多工環境下各任務間共享的標誌應該加 volatile;

3. 儲存器對映的硬體暫存器通常也要加 volatile 說明,因為每次對它的讀寫都可能有不同意義;

另外,以上這幾種情況經常還要同時考慮資料的完整性(相互關聯的幾個標誌讀了一半被打斷了重寫),在1中可以通過關中斷來實現,2中可以禁止任務排程,3中則只能依靠硬體的良好設計了。

儲存器對映的硬體暫存器情況舉栗子:

假設要對乙個裝置進行初始化,此裝置的某乙個暫存器為 0xff800000

int

*output = ( unsigned int* )0xff800000;

int init( void )

}

經過編譯器優化後,編譯器認為前面迴圈半天都是廢話,對最後的結果毫無影響,因為最終只是將 output 這個指標賦值為9,所以編譯器最後給你編譯的**結果相當於:

int init( void )
如果你對此外部裝置進行初始化的過程是必須是像上面**一樣順序的對其賦值,顯然優化過程並不能達到目的。反之如果你不是對此埠反覆寫操作,而是反覆讀操作,其結果是一樣的,編譯器在優化後,也許你的**對此位址的讀操作只做了一次。然而從**角度看是沒有任何問題的。這時候就該使用 volatile 通知編譯器這個變數是乙個不穩定的,在遇到此變數時候不要優化。

volatile

int *output=( volatile

unsigned

int* )0xff800000;

問題:乙個引數是 const 還可以是 volatile 嗎?

可以的,例如唯讀的狀態暫存器。它是 volatile 因為它可能被意想不到地改變,同時也是 const 因為程式不應該試圖去修改它。

C語言volatile關鍵字

volatile 是易變的 不穩定的意思。很多人根本就沒見過這個關鍵字,不知道它的存在。也有很多程式設計師知道它的存在,但從來沒用過它。我對它有種 楊家有女初長成,養在深閨人未識 的感覺。volatile 關鍵字和const 一樣是一種型別修飾符,用它修飾的變數表示可以被某些編譯器未知的因素更改,比...

C語言關鍵字volatile

volatile修飾變數表示該變數易受外界影響發生改變,volatile強烈要求編譯器每次對變數進行訪問都要從記憶體中進行 int a 10 b a c b 當編譯器掃到第一行時10賦給了a 自後a變數的值沒有發生改變,a賦給了b,b賦給了c 由於cpu訪問記憶體的速度較慢,編譯器為了提高效率,直接...

C語言關鍵字 volatile

volatile關鍵字 用法 1 告訴編譯器不做任何優化 2 表示用volatile定義的變數會在程式外被改變,每次都必須要從記憶體中讀取,而不能把它放在cache或暫存器中重複使用 volatile是告訴編譯器對它所修飾的物件別執行優化。volatile在進行多執行緒程式設計時要注意,而在單執行緒...