2012-10-01 96 views
3

我似乎總體上對volatiles有一個合理的理解,但有一個看似不明確的情況,我不確定每個標準應該如何工作。我已經閱讀了C99的相關部分以及SO上的十幾個或更多相關帖子,但無法找到這種情況下的邏輯或解釋這種情況的地方。賦值表達式和volatile

假設我們有這樣的一段代碼:

int a, c; 
    volatile int b; 
    a = b = 1; 
    c = b += 1; /* or equivalently c = ++b; */ 

應該a這樣的評價:

b = 1; 
    a = b; // volatile is read 

或像這樣:

b = 1; 
    a = 1; // volatile isn't read 

同樣,應該c這樣的評價:

int tmp = b; 
    tmp++; 
    b = tmp; 
    c = b; // volatile is read 

或像這樣:

int tmp = b; 
    tmp++; 
    b = tmp; 
    c = tmp; // volatile isn't read 

在簡單的情況下,如a = b; c = b;事情很清楚。但是上面的那些呢?

基本上,問題是,究竟是什麼「表達有分配後左操作數的值」是指在C99的6.5.16c3當對象是揮發性?:

賦值運算符商店由左邊的操作數指定的對象中的值。一個賦值表達式在賦值之後具有左操作數 的值,但不是左值。

它是否意味着要額外讀取volatile以產生賦值表達式的值?

UPDATE

所以,這裏的窘境。

如果未從易失性物體的額外的讀獲得了「分配後的對象的值」,則編譯器作出的假設是,揮發性對象b

  • 是能夠保持任意int值寫入它,它可能不是(比方說,0位是硬連線到0,這與硬件寄存器,這是不尋常的事情,我們應該使用揮發物)
  • 不能改變之間的指定寫入發生時的時間點和獲取表達式值的時間點(並且可能是一個問題與硬件寄存器)

的,因爲所有的和,表達值,如果沒有從所述易失性物體的額外的讀得到,不會產生揮發性物體,其標準權利要求應該是這樣的值。

這兩個假設似乎都不符合易失物體的性質。

如果OTOH是從所述易失性對象的額外隱含讀取中獲得「賦值之後的對象的值」,那麼評估具有易失性左操作數的賦值表達式的副作用取決於是否使用表達式值或者不是或完全是任意的,這將是一個奇怪的,意想不到的和記錄不完善的行爲。

+0

我希望賦值給volatile並不意味着在store之後進行讀取(無論賦值的值是否在其他地方使用都無關緊要)。這意味着標準對volatile變量的映射硬件寄存器定義爲volatile變量(或指向volatile的變量)不會有幾乎所有人都依賴的語義。 –

+0

@MichaelBurr好點。 –

回答

2

C11澄清這是未定義的。

您可以找到C11的最終草稿here。現在引用的第二句是指腳註111:

賦值運算符將值存儲在由左操作數指定的對象中。賦值表達式具有賦值後左操作數的值,但不是左值。

腳註111這樣說:

111)的執行被允許讀取的對象以確定所述值,但不要求,即使當物體具有volatile限定類型。

+0

不錯!所以,基本上,應該避免我在問題中提出的那種代碼,除非可以容忍特定於實現的行爲。 –

+0

@AlexeyFrunze:我認爲這是不可避免的。設想一個硬件地址,它可以讀取上次寫入的任何值的平方根。現在想象一個用N循環延遲來計算它的例子。我認爲標準不能明確定義「賦值後左操作數的值」。它可能需要讀取,但不能規定寫入之後讀取的速度有多快。所以避免執行特定行爲的唯一方法是禁止讀取。 –

+0

@SteveJessop閱讀和閱讀還是有區別的。 C99-應該在這裏更加清晰。 –