volitile變數的使用

2021-05-24 09:35:44 字數 2144 閱讀 7772

volatile 影響編譯器編譯的結果,指出 volatile 變數每次使用時都需要去記憶體裡重新讀取它的值,而一旦修改此變數就直接寫入記憶體,而不是操作cache中的變數。 volatile 變數有關的運算,不要進行特殊優化。

對於上面的**段,優化的作法是,編譯器發現兩次從 i 讀資料的**之間的**沒有對 i 進行過操作,它會從 cache 中把上次讀的資料 i 放在 k 中。而不是重

新從 i 的記憶體裡面讀。這樣以來,如果 i 是乙個暫存器變數或者表示乙個埠資料就容易出錯,所以說 volatile 可以保證對特殊位址的穩定訪問,不會出錯。

我們來看另乙個例子

int volatile i;

while(i)

如果 i 沒有被 volatie 修飾,當 while 迴圈執行時,另一段程式併發的執行了 i=0 ,這個迴圈仍不會退出,因為每次迴圈都是檢查暫存器中的值。

如果有 volatie 修飾,那麼迴圈結束,因為迴圈每次檢查 i 的時候,會先從記憶體把 i 讀入暫存器,這個時候 i 在其它地方被賦 0 ,則迴圈結束。

對於程式中存在多個執行流程訪問同一全域性變數的情況, volatile 限定符是必要的。

此外,雖然程式只有單一的執行流程,但是變數屬於以下情況之一的,也需要 volatile 限定。

1 變數的記憶體單元中的資料不需要寫操作就可以自己發生變化,每次讀上來的值都可能不一樣

2 即使多次向變數的記憶體單元中寫資料,只寫不讀,也並不是在做無用功,而是有特殊意義的

什麼樣的記憶體單元會具有這樣的特性呢?肯定不是普通的記憶體,而是對映到記憶體位址空間的硬體暫存器,例如串列埠的接收暫存器屬於上述第一種情況,而傳送暫存器屬於上述第二種情況。

因此建議使用 volatile 變數的場所:

1 並行裝置的硬體暫存器 2 

乙個中斷服務子程式中會訪問到的非自動變數(全域性變數)

3 多執行緒應用中被幾個任務共享的變數

4 longjmp跳回之後需要保持修改的變數

上面的**分別在非優化和優化條件下將得到不同的結果。

在嵌入式或多執行緒的環境下,不懂得 voliatile 可能會導致災難。我們通過下面幾個問題來加深對其理解。

關鍵字 volatile 有什麼含意 ? 並給出三個不同的例子

1) 乙個引數既可以是 const 還可以是 volatile 嗎?解釋為什麼。

是的。乙個例子是唯讀的狀態暫存器。它是 volatile 因為它可能被意想不到地改變。它是 const 因為程式不應該試圖去修改它。(也就是說, const 指定了我們的程式**中是不可以改變這個變數的,

但是 volatile 指出,可以是由於硬體的原因,在**意外更改這個值,但是我們的**同時會更新使用這個最新的數值)

2) 乙個指標可以是 volatile 嗎?解釋為什麼。

是的。乙個例子是當乙個中服務子程式修該乙個指向乙個 buffer 的指標時。(把指標宣告為 volatile 的型別,可以保證指標所指向的位址隨時發生變化)

3) 下面的函式有什麼錯誤:

int square(volatile int *ptr)

這段**的目的是用來返指標 *ptr 指向值的平方,但是,由於 *ptr 指向乙個 volatile 型引數,編譯器將產生類似下面的**:

int square(volatile int *ptr)

由於 *ptr 的值可能被意想不到地該變,因此 a 和 b 可能是不同的。結果,這段**可能返不是你所期望的平方值!正確的**如下:

int square(volatile int *ptr)

在 signal.h 標頭檔案中宣告了一種 sig_atomic_t 的型別,當把變數宣告為該型別是,則會保證該變數在使用或賦值時,

無論是在 32 位還是 64 位的機器上都能保證操作是原子的,

它會根據機器的型別自動適應。

通常情況下, int 型別的變數通常是原子訪問的,在 linux 裡這樣定義: typedef int __sig_atomic_t; 另外 gnu c 的文件也說比 int 短的型別通常也是具有原子性的,例如 short 型別。同時,指標(位址)型別也一定是原子性的。在 32 位的平台下,訪問 64 位的變數,就不是原子的,而需要兩次讀記憶體操作。 sig_atomic_t 型別的變數應該總是加上 volatile 限定符

,因為要使用 sig_atomic_t 型別的理由也正是要加 volatile 限定符的理由。

c語言中的volitile用法

volatile 影響編譯器編譯的結果,指出,volatile 變數是隨時可能發生變化的,與volatile變數有關的運算,不要進行編譯優化,以免出錯,vc 在產生release版可執行碼時會進行編譯優化,加volatile關鍵字的變數有關的運算,將不進行編譯優化。例如 volatile int i...

c 語言中的 volitile 限定符

volatile關鍵字是一種型別修飾符,用它宣告的型別變數表示可以被某些編譯器未知的因素更改。用volatile關鍵字宣告的變數i每一次被訪問時,執行部件都會從i相應的記憶體單元中取出i的值。沒有用volatile關鍵字宣告的變數i在被訪問的時候可能直接從cpu的暫存器中取值 因為之前i被訪問過,也...

使用變數 Sql 中的變數使用

我們在學 python 或者其他程式語言的時候都應該有學過變數這麼乙個東西,可是 sql 這種查詢語言中怎麼也有變數呢?具體有什麼用呢?我們來看一下實際應用場景。現在有這麼乙個表 t 表結構如下 order id time1 time2 time3 time4 time1 表示瀏覽日期,time2 ...