2009-11-24 98 views
6

對不起,如果這很簡單,我的C++是生鏽的。有點奇怪C++代碼

這是幹什麼的?據我所知,沒有賦值或函數調用。這種代碼模式在我繼承的一些代碼中重複了很多次。如果它很重要,它就是嵌入代碼。

*(volatile UINT16 *)&someVar->something; 

編輯:繼續從那裏,下面的附加代碼確認希斯懷疑嗎? (正好從代碼,包括重複,除了名稱已更改爲保護無辜者)

if (!WaitForNotBusy(50)) 
    return ERROR_CODE_X; 

*(volatile UINT16 *)& someVar->something; 

if (!WaitForNotBusy(50)) 
    return ERROR_CODE_X; 

*(volatile UINT16 *)& someVar->something; 
x = SomeData; 
+1

嵌入式代碼?那麼這可能是一個實際地址,正如沙爾特所懷疑的那樣。 – 2009-11-24 20:22:39

+0

請注意我在下面的答案中添加了一篇文章鏈接:http://www.mjmwired.net/kernel/Documentation/volatile-considered-harmful.txt – Artyom 2009-11-26 11:18:47

+0

這是一個不錯的主意,用'(void)'來避免編譯器警告。所以'(void)*(volatile uint16_t *)&someVar-> something'。當然,用宏或內聯函數包裝它,切勿將它剪切並粘貼到所有位置! – 2015-07-07 23:05:36

回答

19

這是嵌入式編程(儘管它應該封裝在一組函數或宏中)的一個相當普遍的用法,它需要訪問設備寄存器。在許多體系結構中,設備寄存器映射到內存地址,並像任何其他變量一樣被訪問(儘管在固定地址 - 可以使用指針,或者鏈接器或編譯器擴展可以幫助修復地址)。但是,如果C編譯器沒有看到變量訪問的副作用,它可以優化它 - 除非變量(或用於訪問變量的指針)被標記爲volatile。

所以表達;

*(volatile UINT16 *)&someVar->something; 

將發出一個16位在一些偏移讀取(由提供的something結構元素的偏移量)的地址存儲在someVar指針。由於volatile關鍵字,此讀取將發生並且不能由編譯器優化。

請注意,有些設備寄存器即使只是簡單讀取,也會執行一些功能 - 即使讀取的數據未被使用。這在狀態寄存器中很常見,在讀取寄存器之後,錯誤狀態可能會被清除,指示特定位中的錯誤狀態。

這可能是使用volatile關鍵字的更常見原因之一。

+0

謝謝,標記爲答案,因爲我認爲這是最清晰和最完整的答案。 – 2009-11-24 21:53:18

9

我覺得作者的意圖是使編譯器發出在這些點記憶障礙。通過評估易失性的表達式結果,對編譯器的指示是該表達式不應被優化掉,並且應該在每一行「實例化」訪問易失位置的語義(內存障礙,優化的限制)這個習語發生在哪裏。

這種類型的習慣用法可以「封裝」在預處理器宏(#define)中,以防另一種編譯方式導致相同效果。例如,具有直接對讀或寫內存障礙進行編碼的編譯器可能使用內置機制而不是此成語。在宏內部實現這種類型的代碼可以在整個代碼庫中改變方法。

編輯:用戶沙爾斯有很大的點,如果這個碼在指針的地址是一個物理而非虛擬地址(或映射到特定的物理地址的虛擬地址)的環境中運行,那麼執行此讀取操作可能會導致外圍設備發生某些操作。

+2

還有一個宏可以使它更明顯發生什麼...(#define READ_MEMORY_BARRIER ...) – Aaron 2009-11-24 20:09:20

+1

第一步應該是評估它是否確實創建了內存屏障。這似乎是意圖,但許多平臺上的易失性變量只是針對其他易失性變量進行排序。即使它適用於這個嵌入式平臺,它可能不適用於另一個;我會尋找一個更好,更便攜的解決方案來創造障礙。 – 2009-11-24 20:22:36

+1

我不認爲它與內存障礙有關,它是一個嵌入式平臺,它可能將變量映射到某個IO。 – 2009-11-24 20:40:37

9

所以這裏是一個遠射。

如果該地址指向FPGA或其他設備上的存儲器映射區域,那麼當您讀取該地址時,設備可能實際上正在做某些事情。

+0

爲什麼長鏡頭?我認爲這是完全合乎邏輯的解釋。 +1 – 2009-11-24 20:41:10

+0

原來的問題缺乏很多澄清說明,這是在嵌入式系統上發生的,等等。 – 2009-11-26 11:22:58

-1

通常這是錯誤的代碼。

在C和C++中volatile表示很少,並且不提供隱式內存障礙。所以這段代碼是完全錯誤的,它寫成:

memory_barrier(); 
*(volatile UINT16 *)&someVar->something; 

這只是錯誤的代碼。

Expenation:volatile不會使可變原子!

裏德這篇文章:http://www.mjmwired.net/kernel/Documentation/volatile-considered-harmful.txt

這就是爲什麼volatile通常不應在適當的代碼中使用。

+2

呃!?那是什麼意思? – Clifford 2009-11-25 19:19:21