書本裡不會講的C語言關鍵詞volatile用法

2021-10-20 21:28:56 字數 2717 閱讀 3459

volatile用於宣告變數時的使用的限定符。它告訴編譯器該變數值可能隨時發生變化,且這種變化並不是**引起的。給編譯器這個暗示是很重要的。在開始前,我們向來看一看volatile的語法。

c語言關鍵字volatile語法

宣告乙個變數為volatile,可以在資料型別之前或之後加上關鍵字volatile。下面的語句,把foo宣告乙個volatile的整型。

volatile int foo;

int volatile foo;

把指標指向的變數宣告為volatile很常見,尤其是i/o暫存器的位址對映。下面的語句,把preg宣告為乙個指向8-bit無符號指標,指標指向的內容為volatile。

volatile uint8_t * preg;

uint8_t volatile * preg;

volatile的指標指向非volatile的變數很少見(我只使用過一次),但我還是給出相應的語法。

int * volatile p;

最後,如果你再struct或者union前使用volatile關鍵字,表明struct或者union的所有內容都是volatile。如果這不是你的本意,可以在struct或者union成員上使用volatile關鍵字。

正確使用c語言關鍵字volatile

只要變數可能被意外的修改,就需要把該變數宣告為volatile。實際應用中,只有三種型別資料可能被修改。

1. 外設暫存器位址對映

2. 在中斷服務程式中修改全域性變數

3. 在多執行緒、多工應用中,全域性變數被多個任務讀寫

我們將分別討論上述三種情況。

外設暫存器

嵌入式系統包含真正的硬體,通常會有複雜的外設。這些外設暫存器的值可能被非同步的修改。舉個簡單的例子,我們要把乙個8-bit狀態暫存器的位址對映到0x1234.在程式中迴圈檢視該狀態暫存器的值是否變為非0. 下面是最容易想到,但錯誤的實現方法

當你開啟編譯器優化時,程式總是執行失敗。因為編譯器會生成下面的彙編**:

程式被優化的原因很簡單,既然已經把變數的值讀入累加器,就沒有必要重新一遍,編譯器認為值是不會變化的。就這樣,在第三行,程式進入了無限死迴圈。為了告訴編譯器我們的真正意圖,我們需要修改函式的宣告:

編譯器生成的彙編**:

像這樣,我們得到了正確的動作。

中斷服務程式

在中斷服務程式中,經常會修改一些全域性變數值,來作為主程式中的判斷條件。例如,在串列埠中斷服務程式中,可能會檢測是否接收到了etx(假如是訊息的結束識別符號)字元。如果接收到了etx,isr設定乙個全域性標誌位。

錯誤的做法:

在關閉編譯器優化的情況下,程式可能執行正常。然而,任何像樣點而優化都會「break」這段程式。問題是編譯器並不知道etx_rcvd可能被isr中被修改。編譯器只知道,表示式!ext_rcvd始終為真,你講用於無法退出迴圈。結果,迴圈後面的**可能被編譯器優化掉。幸運的話,你的編譯器可能會發出警告;不幸的話,(或者你不認真的檢視編譯器警告),你的程式無法正常執行。當然,你可以責怪編譯器執行了「糟糕的優化」。

解決方式是,將變數etx_rcvd宣告為volatile,所有問題(當然,也可能是部分)就消失了。

多執行緒應用

在實時系統中,儘管有想queues,pipes等這些同步機制,使用全域性變數實現兩個任務共享資訊的做法依然很常見。即使在你的程式中加入了搶占式排程器,你的編譯器依然無法知道什麼是上下文切換,或何時發生上下文切換。因此,從概念上講,多工修改全域性變數的的做法與中斷服務程式中修改全域性變數的做法是相同的。因此,所有這類全域性變數都應該宣告為volatile。例如,下面的程式

當開啟編譯器優化時,這段程式可能執行失敗。解決方法是將cntr宣告為volatile。

最後的思考

一些編譯器允許你把所有的變數隱式的宣告為volatile。請抵制這種**,因為它會令你不再思考,當然,也會導致生成低效的**。

另外,也不要責怪優化器或直接把它關掉。現代的優化器已經足夠優秀,我已經記不清上次遇到優化bug是什麼時候了。相反,我常常看到程式設計師們錯誤的使用volatile。

如果你被要求去修改乙個很古怪的**,請在程式中查詢一下volatile關鍵字,如果你什麼也沒有找到上面討論的例子可以向你提供一些解決問題的思路。

C語言 關鍵詞static解釋

static static在c語言中可以修飾變數或者函式。總得來說,用static修飾的變數或是函式具有靜態的特性。static修飾區域性變數 static修飾區域性變數的主要改變在於改變了區域性變數的生命週期。一般的區域性變數,生命週期都是在它的函式內,在函式結束的時候,就會釋放變數。再次進入函式...

C語言中的static關鍵詞

另一種是區域性變數,如在for迴圈中定義的變數,在函式中的變數,這樣的變數在 快執行時則有效,一旦執行完畢,則會立即被系統從記憶體中清理出去.1.函式內部 普通函式中的變數,隨函式的執行而存在,而在函式內部加上static修飾的變數,則隨函式的存在而存在,主要前面是執行,後面是函式的存在,當stat...

C語言32關鍵詞分類詳解

auto double intstruct break else long switch case enum register typedef char extern return union const float short unsigned continue forsigned void de...