2011年8月5日 星期五

簡介C語言volatile關鍵字及其陷阱

volatile變數代表其所儲存的內容會不定時地被改變,宣告volatile變數用來告訴編譯器 (Compiler) 不要對該變數做任何最佳化操作,凡牽涉讀取該volatile變數的操作,保證會到該變數的實體位址讀取,而不會讀取CPU暫存器的內容 (提升效能) 。舉個例子,某一硬體狀態暫存器 (Status Register)就必須宣告volatile關鍵字,因為該狀態暫存器會隨時改變,宣告volatile便可確保每次讀取的內容都是最新的。

Volatile關鍵字的應用範疇
1. 硬體暫存器,如狀態暫存器。
2. 多執行緒所共用的全域變數。
3. 中斷服務函式 (Interrupt Service Rountie,ISR)所使用的全域變數。


Volatile陷阱
想想底下範例是否有問題?


#include <stdio.h>

int square(volatile int *var)
{
return *var **var;
}

int main(void)
{
int var = 5;

printf("result: %d\n", square(&var));
return 0;
}


其問題在於square函式的平方算式,*var**var,此指令代表到var位址讀取其內容。然而,var位址可能儲存硬體暫存器,這些暫存器內容會隨時間而改變 (例如: 狀態暫存器),有可能第一次讀取的時候為4, 下一次讀取為5, 導致計算出來的值不正確。

因此,避免此錯誤發生便是在square函式宣告一local變數,看底下程式範例較為清楚:



#include <stdio.h>

int square(volatile int *var)
{
int local_var = *var;

return local_var * local_var;

}

int main(void)
{
int var = 5;

printf("result: %d\n", square(&var));
return 0;
}


【Reference】
[1] How to Use C's volatile Keyword

沒有留言: