C語言中的volatile——讓我保持原樣


volatile譯為:易變的。這不是和題目的讓我保持原樣矛盾了嗎?其實不然,在變量前加上該關鍵字修飾,確實是告訴編譯器,這個變量是一個容易改變的變量,不要對它進行優化,每次都要到變量的地址中去讀取變量的數據,但正因為這樣,才是保持了變量的原樣,因為變量已經發生改變了,你卻操作的是沒有變化時的數據,這樣才讓變量失去了本應該保持的屬性。

eg:

int a=1;

a=2;

a=3;

....

編譯器看到這樣的代碼,會覺得a的值只有a=3才有意義,所以把a存儲在一個寄存器中,每次遇到a都在這個寄存器中去讀取數據,但是a是可能改變,比如中斷或者多線程的時候。這個有可能你測試它又是正確的,因為隨着你的優化等級提高,生成的匯編代碼會有很大不同,如果基礎不夠扎實,代碼的魯棒性就會減弱,要想不這樣,那么需要程序員有足夠扎實的基本功。

1.我們先看volatile第一個應用場景,在中斷服務函數中的使用。

/*   main.c */

int flag=0;

int main(void)

{

  if(flag==1)

    {do somethings}

  if(flag==2)

        {do somethings}

  return 0;

}

/* interrupt*/

void NVIC_Handler(void)

{

  flag=1;

}

在這種情況下,編譯器可能會對其做優化,雖然中斷服務函數改變了flag的值,但是編譯器並沒有在變量內存中去讀取,而是在寄存器中讀取了flag之前的緩存數據。在中斷函數中的交互變量,一定要加上volatile關鍵字修飾,這樣每次讀取flag的值都是在其內存地址中讀取的,確保是我們想要的數據。

2.多任務環境下各任務間共享的標志應該加volatile。原因其實和上面中斷一樣,要共享標志,又不想讓編譯器優化了這一點,需要加上該修飾詞。

3.存儲器映射的硬件寄存器通常也要加voliate,因為每次對它的讀寫都可能有不同意義。

以STM32為例,寄存器中的數據也是時刻在變化的,我們也不想編譯器優化這一點,所以在庫函數中我們可以看到這樣的代碼。

這是寄存器的結構體,我們查看前綴__I 和__IO到底是什么?

 

 可以看到,在寄存器的映射中,也需要volatile,因為寄存器的值也是可能隨時更改的。

通過上面,我們也應該明白那個問題。

一個參數既可以是const還可以是volatile嗎?

可以的,例如只讀的狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應該試圖去修改它。軟件不能改變,並不意味着我硬件不能改變你的值,這就是單片機中的應用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM