易變數

volatile 關鍵字告訴編譯器,由於外部條件,變數的值可能隨時發生變化,而不僅僅是程式控制流的結果。

編譯器不會優化與 volatile 變數有關的任何內容。

volatile int foo; /* Different ways to declare a volatile variable */
int volatile foo;

volatile uint8_t * pReg; /* Pointers to volatile variable */
uint8_t volatile * pReg;

使用 volatile 變數有兩個主要原因:

  • 與具有記憶體對映 I / O 暫存器的硬體介面。
  • 使用在程式控制流程外修改的變數時(例如,在中斷服務程式中)

我們來看看這個例子:

int quit = false;

void main() 
{
    ... 
    while (!quit) {
      // Do something that does not modify the quit variable
    } 
    ...
}

void interrupt_handler(void) 
{
  quit = true;
}

允許編譯器注意 while 迴圈不修改 quit 變數並將迴圈轉換為無限的 while (true) 迴圈。即使在 SIGINTSIGTERM 的訊號處理程式上設定了 quit 變數,編譯器也不知道。

quit 宣告為 volatile 將告訴編譯器不優化迴圈,問題將得到解決。

訪問硬體時會出現同樣的問題,如本例中所示:

uint8_t * pReg = (uint8_t *) 0x1717;

// Wait for register to become non-zero 
while (*pReg == 0) { } // Do something else

優化器的行為是讀取變數的值一次,不需要重新讀取它,因為值總是相同的。所以我們最終得到了一個無限迴圈。為了強制編譯器執行我們想要的操作,我們將宣告修改為:

uint8_t volatile * pReg = (uint8_t volatile *) 0x1717;