宣告變數 Volatile(揮發) 顧名思義揮發性的變數宣告。
在了解Volatile 之前必須先搞懂一件事,就是processes中變數的處理方式,簡單來說當program 中宣告,當宣告一個變數後此變數會暫存在CPU 的cache中,以方便快速的運算,直到processes結束。
Volatile 使用時機:
很多時候compiler 可以依據各種不同取向與需求而進行不同的最佳化,包括執行速度最快化、程式容量佔量最小化、針對某種硬體系統所能發揮運用的指令來最適化等。但是有時最佳畫會造成程式執行有誤,宣告volatile變數用來告訴編譯器(Compiler) 不要對該變數做任何最佳化操作,最常見的錯誤如以下兩種:
1, I/O
假設有一程式片斷如下
U8 *pPort;
U8 i, j, k;
pPort = (U8 *)0x800000;
i = *pPort;
j = *pPort;
k = *pPort;
以上的i, j, k很有可能被compiler最佳化而導致產生
i = j = k = *pPort;
的code, 也就是說只從pPort讀取一次, 而產生 i = j = k 的結果, 但是原本的程式的目的是要從同一個I/O port讀取3次的值給不同的變數, i, j, k的值很可能不同(例如從此 I/O port 讀取溫度), 因此i = j = k的結果不是我們所要的怎麼辦
用volatile, 將
U8 *pPort;
改為
volatile U8 *pPort;
告訴compiler, pPort變數具有揮發性的特性, 所以與它有關的程式碼請不要作最佳化動作. 因而
i = *pPort;
j = *pPort;
k = *pPort;
此三列程式所產生的code, 會真正地從pPort讀取三次, 從而產生正確的結果
2. Global variables in Multithread Program
這是在撰寫multithread program時最容易被忽略的一部份
此原因所造成的bug通常相當難解決(因為不穩定)
假設有以下程式片斷, thread 1 & thread 2共用一個global var: gData
thread 1: thread 2:
... ....
int gData; extern int gData;
while (1) int i, j, k;
{
.... for (i = 0; i < 1000; i++)
gData = rand(); {
..... /* A */
} j = gData;
....
.... }
在thread 2的for loop中, 聰明的compiler看到gData的值, 每次都重新從memory load到register,
實在沒效率, 因此會產生如下的code(注意,tmp也可以更進一步的用register取代):
tmp = gData;
for (i = 0; i < 1000; i++
{
/* A */
j = tmp;
....
}
也就是gData只讀取一次, 這下子問題來了, 說明如下:
thread 2在執行for loop到j = gData的前一列(A)的時候(假設此時gData=tmp=5),
被切換到thread 1執行在thread 1的while loop中透過gData = rand(), 對gData做了修改(假設改為1), 再切換回thread2執行
繼續執行 j = gData, 產生j = 5的結果
但是正確的結果應該是 j = 1
怎麼辦 => 也是用volatile
在thread 1中, 將
int gData;
改為
volatile int gData;
在thread 2中, 將
extern int gData;
改為
extern volatile int gData;
Const
用來定義常數 (constant) ,凡是以 const 宣告後的變數 (variable) 設定初值後,都不能重新指派新的值。一般來說大家會把他解讀為『常數』,但是這樣的解釋好像有點點不足,應該要解讀為 read-only 比較恰當。
const 與 #define 又有甚麼不同呢?
#define =>可建立巨集 Macro, 或宣告常用常數使用是一種pre-compile header
會在程式編譯成機械語言前先編譯好所以程式在執行時會較快 較省空間(但也有說法 現代的編譯器用define or const所編出來的code品質是相當的)
const =>宣告常數使用(且是一個可定址的常數資料)
常數欄位和區域常數不是變數,可能無法修改。
常數可以是數值、布林值、字串或 null 參考。 請勿建立用來表示想隨時變更之資訊的常數。
C/C++中的volatile使用時機
沒有留言:
張貼留言