讀古今文學網 > C語言解惑 > 14.6 使用volatile變量 >

14.6 使用volatile變量

volatile影響編譯器編譯的結果。如果沒有volatile關鍵字,則編譯器可能優化讀取和存儲,即在本次線程內,當讀取一個變量時,為提高存取速度,編譯器優化時會先把變量讀取到一個寄存器中,以後再取變量值時,就直接從寄存器中取值。

volatile則提醒編譯器,用它所定義的變量隨時都有可能發生變化,因此編譯後的程序每次需要存儲或讀取這個變量的時候,都需要直接從變量地址中讀取數據。

【例14.20】分析下面函數能否實現延時的功能。


void delay
(void
)
{
       int i
;
       int result
;
       for
(i=0
; i < 1863
; ++i
)
            result = 12* 35
;
}
  

【分析】不能。編譯器知道12*35的結果為420,因此他沒有做乘法而是通過優化處理直接給出「result=420」,從而關閉了計時功能。

如果使用兩個變量,及聲明


int num1 = 12
,num2 = 35
;
  

使用語句


result = num1 * num2
;
  

也是不能實現計時的。一般與編譯器的選擇開關有關。這裡針對一般的情況,因為優化器知道儘管該函數計算了result的值,但它仍然沒有做任何處理。因此,無論result是否已經計算過,程序的執行都不會改變。於是,優化器發現如下循環:


for
( i=0
; i < 1863
; ++i
)
{
      result = num1 * num2
;
}
  

就將其優化為:


for
( i=0
; i < 1863
; ++i
)
{
     // Do nothing
}
  

顯然,不需要將Do nothing重複420次,因此程序就被優化為:


// No loop needed
{
     // Do nothing
}
  

要阻止優化的方法是將result聲明為volatile。但這也沒有徹底解決問題,因為優化器很靈敏,它發現正在計算for循環體的


num1 * num2
;
  

時,會把程序優化成只做一次乘法。


int register1 = num1 * num2
;
for
( i=0
; i < 1863
; ++i
)
{
        result = register1
;
}
  

如果都使用volatile,就會克服這個問題。


//
修改後的程序
void delay
(void
)
{
     int i
;
     volatile int result
;
     volatile int num1 = 12
;
     volatile int num2 = 35
;
     for
( i=0
; i < 1863
; ++i
)
     {
             result = num1 * num2
;
     }
}