C語言中的volatile
volatile的定義:
Indicates that a variable can be changed by a background routine.
Keyword volatile is an extreme opposite of const.It
indicates that a variable may be changed in a way which is absolutely unpredictable by analysing the normal program flow (for example, a variable which may be changed by an interrupt handler). This keyword uses the following syntax:
翻譯為表示一個變數也許會被後臺程式改變,關鍵字 volatile 是與 const 絕對對立的。它指示一個變數也許會被某種方式修改,這種方式按照正常程式流程分析是無法預知的(例如,一個變數也許會被一箇中斷服務程式所修改)。
變數如果加上volatile,就會從記憶體中重新裝載內容,而不是從暫存器中拷貝內容。volatile 的作用 是作為指令關鍵字,確保本條指令不會因編譯器的優化而省略,且要求每次直接讀值。
volatile主要由一下幾種應用場合:
1). 並行裝置的硬體暫存器(如:狀態暫存器)
#define GPC1CON *((volatile unsigned int*)0xE0200080)typedef const int32_t sc32; /*!< Read Only */
#define GPC1DAT *((volatile unsigned int*)0xE0200084)
#define GPC1PUD *((volatile unsigned int*)0xE0200088)
...........
typedef const int16_t sc16; /*!< Read Only */
typedef const int8_t sc8; /*!< Read Only */ typedef __IO int32_t vs32;
typedef __IO int16_t vs16;
typedef __IO int8_t vs8; typedef __I int32_t vsc32; /*!< Read Only */
typedef __I int16_t vsc16; /*!< Read Only */
typedef __I int8_t vsc8; /*!< Read Only */ typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8; typedef const uint32_t uc32; /*!< Read Only */
typedef const uint16_t uc16; /*!< Read Only */
typedef const uint8_t uc8; /*!< Read Only */ typedef __IO uint32_t vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t vu8; typedef __I uint32_t vuc32; /*!< Read Only */
typedef __I uint16_t vuc16; /*!< Read Only */
typedef __I uint8_t vuc8; /*!< Read Only * .............. #ifdef __cplusplus #define __I volatile /*!< defines 'read only' permissions */ #else
#define __I volatile const /*!< defines 'read only' permissions */
#endif
#define __O volatile /*!< defines 'write only' permissions */
#define __IO volatile /*!< defines 'read / write' permissions */
一個引數既可以是const還可以是volatile嗎?
可以的,例如只讀的狀態暫存器。它是volatile因為它可能被意想不到地改變。它是const因為程式不應該試圖去修改它。軟體不能改變,並不意味著我硬體不能改變你的值,這就是微控制器中的應用。
2). 一箇中斷服務子程式中會訪問到的非自動變數(Non-automatic variables)
/* 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的值都是在其記憶體地址中讀取的,確保是我們想要的資料。
3). 多執行緒應用中被幾個任務共享的變數
原因其實和上面中斷一樣,要共享標誌,又不想讓編譯器優化了這一點,需要加上該修飾詞。
簡潔的說就是:volatile關鍵詞影響編譯器編譯的結果,用volatile宣告的變量表示該變數隨時可能發生變化,與該變數有關的運算,不要進行編譯優化,以免出錯