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

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

例如:緩存

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,由於每次對它的讀寫均可能有不一樣意義。spa

以STM32爲例,寄存器中的數據也是時刻在變化的,咱們也不想編譯器優化這一點,因此在庫函數中咱們能夠看到這樣的代碼。線程

這是寄存器的結構體,咱們查看前綴__I 和__IO究竟是什麼?code

能夠看到,在寄存器的映射中,也須要volatile,由於寄存器的值也是可能隨時更改的。blog

經過上面,咱們也應該明白那個問題。

 

一個參數既能夠是const還能夠是volatile嗎?

 

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

相關文章
相關標籤/搜索