C99標準是否允許將變量分配給自己?舉例來說,有以下幾種有效:C99標準是否允許爲自己分配一個變量?
int a = 42;
/* Case 1 */
a = a;
/* Case 2 */
int *b = &a;
a = *b;
雖然我懷疑病例1是有效的,我很猶豫,說同樣的情況2
在轉讓的情況下,是右側完全評估之前將值分配給左側的變量 - 或者是取消引用指向所分配的變量的指針時引入的競爭條件?
C99標準是否允許將變量分配給自己?舉例來說,有以下幾種有效:C99標準是否允許爲自己分配一個變量?
int a = 42;
/* Case 1 */
a = a;
/* Case 2 */
int *b = &a;
a = *b;
雖然我懷疑病例1是有效的,我很猶豫,說同樣的情況2
在轉讓的情況下,是右側完全評估之前將值分配給左側的變量 - 或者是取消引用指向所分配的變量的指針時引入的競爭條件?
兩種情況都是完全有效的,因爲a
的值僅用於確定要存儲的值,而不是確定要存儲該值的對象。
在你必須區分三種不同的操作
這三個操作中的前兩個操作可以以任何順序完成,即使並行。第三個顯然是另外兩個的結果,所以它會出現。
這是完全有效的,你只使用以前的值來確定要存儲的值。這是包括在draft C99 standard部6.5.2
它說:
之前和下一序列點之間的對象應具有由 expression.Furthermore的評價中,前一個值改性至多一次其 儲值只讀爲 確定要存儲的值。
之一的有效代碼的示例如下:
i = i + 1;
C和C++部here涵蓋可以發生的序列點不同的地方。
假設編譯器不會通過簡單地刪除第一條指令來優化第一條指令,這裏甚至存在競爭條件。在大多數體系結構中,如果a被存儲在內存中,a = a
將被編譯爲兩條移動指令(mem => reg,reg => mem),因此不是原子性的。
下面是一個例子:
int a = 1;
int main()
{ a = a; }
在Intel x86_64的用gcc結果4.7.1
4004f0: 8b 05 22 0b 20 00 mov 0x200b22(%rip),%eax # 601018 <a>
4004f6: 89 05 1c 0b 20 00 mov %eax,0x200b1c(%rip) # 601018 <a>
但你是*假設*,你試過嗎?爲什麼沒有任何編譯器不能刪除它?它很容易做到檢測。這是你真實的例子嗎?哪個編譯器? –
雖然@GrijeshChauhan可能是正確的,現代編譯器很可能不會這樣做,但我對C99標準是否允許這種行爲感興趣 - 畢竟,編譯器不必*實用*成爲*符合標準*。 –
hmm hivert推出了它會是如果編譯器不優化它,所以它的好答案。 –
C99 6.5.16。1簡單賦值
3如果被存儲在一個對象的值是從以任何方式 第一個對象的存儲重疊的另一目的讀取,則重疊應爲精確和兩個對象應 有資格或兼容類型的非限定版本;否則,行爲是未定義的 。
我認爲示例代碼限定了「重疊」條件。由於它們具有兼容類型的限定版本,因此結果是有效的。
另外6.5.16賦值運算符
4的操作數的評價的順序是不確定的。如果嘗試修改賦值運算符的結果或在下一個序列點之後訪問它,則 行爲未定義。
仍然沒有「嘗試修改結果」,所以結果是有效的。
關於段落4('如果試圖修改賦值操作符的結果或在下一個序列點之後訪問它,行爲是未定義的。因爲'a'在評估之前被修改:'a = ++ a'?什麼是*序列點*? –
@VilhelmGray這是一個關於序列點的很好的參考:http://en.wikipedia.org/wiki/Sequence_point它有一個關於C和C++的部分,什麼是序列點。 –
@VilhelmGray是的,這是正確的,幻燈片197有這個例子:http://www.slideshare.net/olvemaudal/deep-c和這個頁面有更多這樣的例子:https://www.securecoding.cert.org /confluence/display/seccode/EXP30-C.+Do+not+depend+on+order+of+evaluation+between+sequence+points –
我看不到C編譯器而不是允許a = a
。由於沒有程序員知道它的宏,這種分配可能偶然發生。它甚至可能不會生成任何代碼,這是一個優化問題。
#define FOO (a)
...
a = FOO;
示例代碼很容易編譯,我對C標準的審查顯示不禁止。
至於比賽條件@於皓回答得好:沒有比賽條件。
'a = a;'是高級語言中的死指令,我非常肯定優化階段會將其刪除 –
@GrijeshChauhan並不總是如果a在內存中並且不需要優化。看我下面的例子。 – hivert
只要變量已經正確初始化,你應該沒問題。如果變量未初始化,則複製未初始化的值不會使其更好地初始化。如果變量是volatile,它可能不是空操作(編譯器必須讀取該值並寫入再次讀回的值)。當變量不符合volatile時,它應該是no-op。 –