volatile 令變數具有可見性& volatile避免指令優化重排. 下面有段程式碼. 有一個 member ... ... <看更多>
volatile變數 在 [分享][C語言測試] 想成為嵌入式程式員應知道的0x10個基本 ... 的推薦與評價
內(但在函數體外),一個被宣告為靜態的變數可以被Block內所有的函數存取, ... 一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設 ... ... <看更多>
volatile變數 在 易變數| 他山教程,只選擇最優質的自學材料 的推薦與評價
編譯器不會優化與volatile 變數有關的任何內容。 placeholderCopy volatile int foo; /* Different ways to declare a volatile variable */ int volatile ... ... <看更多>
volatile變數 在 Re: [問題] Volatile陷阱- 精華區C_and_CPP - 批踢踢實業坊 的推薦與評價
※ 引述《yshihyu (yshihyu)》之銘言:
: https://adrianhuang.blogspot.tw/2011/08/cvolatile.html
: 程式碼我是看這網站
你應該去看看它下面的參考資料
【Reference】
[1] How to Use C's volatile Keyword
https://www.barrgroup.com/Embedded-Systems/How-To/C-Volatile-Keyword
至於 blogspot 那篇建議別看,因為那是作者讀完參考資料以後自己隨便舉的例。
: #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;
: }
這個例子最失敗的地方就是放了 main function,
然後 main function 又不經大腦思索就隨便亂寫。
這代表了這個例子是個完整程式,square() 的唯一 caller 就是 main()。
因為 var 必然是 main() 的 stack frame 裡存放 local variable 的某個 slot,
而這個 slot 的 address 是由 compiler 去決定的,
code 裡也沒任何特殊的元素去指明 var 應該被怎樣特別對待,
所以這個 var 的值壓根就不會有任何 compiler 意料之外的變動。
既然他根本懶得設計 square() 的 caller,其實他只放這樣就能暗示無限多種可能:
int sqaure(volatile int *var)
{
return *var * *var;
}
: 其問題在於square函式的平方算式,*var**var,此指令代表到var位址讀取其內容。然而
: ,var位址可能儲存硬體暫存器,這些暫存器內容會隨時間而改變 (例如: 狀態暫存器),
: 有可能第一次讀取的時候為4, 下一次讀取為5, 導致計算出來的值不正確。
: 可是前面又提到 凡牽涉讀取該volatile變數的操作,保證會到該變數的實體位址讀取,而不會讀取CPU暫
: 存器的內容 (提升效能) , 這樣這程式碼變數加上 volatile 都會從記憶體取值,這樣不是沒問題?
: 怎麼感覺講法有衝突,還是我誤解他意思?
:
: 他說正確解法是在square函式宣告一local變數
: int square(volatile int *var)
: {
: int local_var = *var;
: return local_var * local_var;
: }
: 謝謝
所以大家常說要讀書就要讀外文書或中譯本。
因為外國的月亮雖然未必真的比較圓,但是事實上卻常常比本國的圓很多很多。
volatile int *var 代表什麼意思?
代表 var 是一個 pointer,指向一個 volatile int 的資料。
換句話說是被指之物 (位於記憶體上) 具備 volatile 的特性,
而不是 var (也就是 pointer 本身) 具備 volatile 的特性。
來讀一下該文作者寫了什麼東西:
「其問題在於square函式的平方算式,*var**var,此指令代表到var位址讀取其內容。
然而,var位址可能儲存硬體暫存器,這些暫存器內容會隨時間而改變
(例如: 狀態暫存器),有可能第一次讀取的時候為4, 下一次讀取為5,
導致計算出來的值不正確。 」
既然他本段中寫到「*var**var」,那麼這所指的 var 必為 sqaure() 內的 var。
什麼叫「var位址」?這是中文的模稜兩可之處,所以中文技術文章不應該用這種用語。
如果解讀成「var 的位址」,那麼顯然不通,因為這段程式沒有取 var 的位址。
但是如果讀者執意這麼認為,他就會把這個當成 main function 的 var,產生混亂。
這個「var位址」真要寫的話,應該寫成「位址var」比較正確。
而作者之所以這樣寫,只是想表達 var 是個 pointer 罷了,但根本沒必要。
「var位址可能儲存硬體暫存器,這些暫存器內容會隨時間而改變」這也是很糟的句子。
我不管怎麼讀,都很像是程式把其它國語言硬翻成中文一樣,完全不通順。
「var位址」是主詞,「儲存」是動詞,「硬體暫存器」是受詞。
世界上有什麼 pointer 或 address 本身可以拿來「儲存」硬體暫存器?沒有。
根據他的參考資料,可以發現這段想說的叫做 memory-mapped registers。
因為各位很多是大學直接讀外文書,可能很少人知道 memory-mapped 的正式譯法。
這個形容詞的翻譯方式叫「記憶體映射」,所以上文的「儲存」應當寫成「映射」。
也就是說,前文的「硬體暫存器」所指的暫存器,並不是很多讀者誤會的那種暫存器。
每次讀取 *var 的動作,可能是從某個週邊裝置循序讀取一筆資料;
每次寫入 *var 的動作,可能是對某個週邊裝置循序寫入一筆資料。
意思是 *var 這塊空間可能是被投射到該週邊裝置上的某個暫存器上,
該週邊裝置可能定時檢查這個暫存器的值有無變化,有變化就會進行某些操作;
讀取該暫存器的動作,可能觸發該週邊裝置去執行某項操作,然後把一個值更新進去;
該週邊裝置可能不斷在做某件事,不斷更新該暫存器的內容,所以值常常讀出來不一樣。
這文章的作者第一段把兩種暫存器混在一起,又沒有特別提及 memory-mapped 這關鍵字,
坦白說我有點懷疑他自己其實不懂,也沒讀通他參考原文的意思。
不過姑且可以理解成他只讀外文書,所以中文文章不知道該怎麼寫了吧。
據說這是某公司的面試考題,如果這是真的...
我只能說直接把網路上的東西複製下來當考題,這出題者也實在太沒誠意了。
--
Ling-hua Tseng ([email protected])
Andes Technology Corporation
Compiler Group of RD/Software Division
Homepage: https://blog.tinlans.org
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 220.132.55.117
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1439588699.A.D28.html
※ 編輯: tinlans (220.132.55.117), 08/17/2015 22:44:39
... <看更多>