易失性寫入易失性常量是否引入未定義的行爲?如果我在寫作時跌跌撞撞地怎麼辦?volatile變量的間接變化可以視爲未定義的行爲?
volatile const int x = 42;
const volatile int *p = &x;
*(volatile int *)p = 8; // Does this line introduce undefined behavior?
*(int *)p = 16; // And what about this one?
易失性寫入易失性常量是否引入未定義的行爲?如果我在寫作時跌跌撞撞地怎麼辦?volatile變量的間接變化可以視爲未定義的行爲?
volatile const int x = 42;
const volatile int *p = &x;
*(volatile int *)p = 8; // Does this line introduce undefined behavior?
*(int *)p = 16; // And what about this one?
這是不確定的行爲(兩個語句),你試圖修改 「初始」 const
對象。從C11(N1570)6.7.3/P6 類型限定符(重點煤礦):
如果試圖修改通過使用左值的與 常量限定類型定義的對象與非-const-qualified 類型,行爲是未定義的。
爲了完整性它可能是值得增加,即標準也說:
如果試圖指通過使用左值的與具有 volatile限定類型定義的對象 非易失性限定類型,行爲未定義。
因此後者語句,即:
*(int *)p = 16;
是未定義第二短語,以及(這是一個 「雙UB」)。
我相信C++的規則是一樣的,但是並不擁有C++ 14的副本來確認。
像我的回答說,修改一個'const'值是無效的 - 但是,它刪除'volatile'無效 - 它只會讓編譯器潛在地緩存全局值。 –
@MatsPetersson:希望我的回答現在更清楚。是的,你是對的,你可以放棄'volatile'限定詞,這不是UB。 –
而常量被聲明爲volatile的事實不影響這種說法嗎? – Qwertiy
寫入最初爲const
的變量是未定義的行爲,因此您所有寫入*p
的示例均未定義。
刪除volatile
本身並不是未定義的。
但是,如果我們有像const volatile int *p = (const volatile int*)0x12340000; /* Address of hw register */
這樣的東西,那麼刪除volatile
可能會導致硬件更新寄存器值,但是您的程序不會檢測到它。 (例如,如果我們「忙於等待」while(*p & 0x01) ;
,編譯器應該每次都重新加載p
指向的值,但while((*(const int *)p) & 1) ;
,編譯器完全可以自由讀取值1,並且如果有一點再次使用初始值循環0被設定)。
你當然可以有
[編輯,不,拿走extern volatie int x;
然後用
const volatile int *p = &x;
在一些代碼,並
x
得到您的當前轉換單元之外的一些其他的代碼更新(例如另一個線程) - 在這種情況下刪除或者
const
或
volatile
是有效,但如上所述,您可能會「錯過」更新的值,因爲除非您調用函數,否則編譯器不希望全局值在模塊外更新。
volatile
通過鑄造該值也是被禁止的標準 - 但是將const
或volatile
添加到某個東西然後再刪除它,如果它原來的對象沒有它]。
需要Edti2:volatile
來告訴編譯器「即使您認爲什麼都不應該改變它,值可能隨時改變」。發生這種情況,在一般情況下,在兩種情況:即在軟件的外面完全更新
注意volatile
不是任何種類的線程/進程的正確性的保障 - 它只是保證編譯器不會跳過讀取或寫入該變量。程序員仍然需要確保例如依賴於排序的多個值確實以正確的順序更新,並且在高速緩存在處理單元之間不一致的系統上,通過軟件使高速緩存一致[for例如,一個CPU和一個GPU可能不會使用連貫的內存更新,因此CPU寫入直到CPU上的緩存已被刷新纔會寫入GPU - 不會將代碼volatile
應用於此代碼將修復此問題]
相關到[如何在同一地址產生2個不同的值的變量?](http://stackoverflow.com/q/22656734/1708801) –