2010-07-19 84 views
8

可能重複:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)後遞增操作:意外的行爲

我的代碼如下:

#include <stdio.h> 
int main() 
{ 
    int x = 10, y = 0; 
    x = x++; 
    printf("x: %d\n", x); 
    y = x++; 
    printf("y: %d\n", y); 
} 

考慮後遞增的性質,我會期望以下輸出:

x: 10 
y: 10 

我的推理是,在第5行中,x應該在增量發生後分配給它的初始值。

相反,不過,我得到這個:

x: 11 
y: 11 

挖掘到組裝,這看起來像一個深思熟慮的選擇對我說:

LCFI2: 
     movl $10, -4(%rbp) // this is x 
     movl $0, -8(%rbp) // this is y 
     incl -4(%rbp)  // x is simply incremented 
     movl -4(%rbp), %esi 
     leaq LC0(%rip), %rdi 
     movl $0, %eax 
     call _printf 
     movl -4(%rbp), %eax // now x is saved in a register, 
     movl %eax, -8(%rbp) // copied to y, 
     incl -4(%rbp)  // and finally incremented 
     movl -8(%rbp), %esi 
     leaq LC1(%rip), %rdi 
     movl $0, %eax 
     call _printf 

這是怎麼回事? GCC是否試圖從我身上拯救我?我沒有一個方便的語言參考,但我會認爲這打破了預期的語義。

+0

可憎的事! – 2010-07-19 02:32:59

+0

http://en.wikipedia.org/wiki/Sequence_point – Ken 2010-07-19 02:59:32

+0

在過去不好的日子裏,某些語言中的「a = 1 + a」是所有新bug都會遇到的問題。 – 2010-07-19 09:58:43

回答

13

該行爲未定義,因爲x = x++中沒有插入序列點,請參閱C FAQ

+0

謝謝!我以前並不知道序列點。 – danben 2010-07-19 11:56:01

4

C語言未定義何時發生後/預加/減法。因此,諸如x = x++之類的陳述不正確 - 避免它們。

+1

更準確地說,您不允許在表達式中多次修改變量。 6。5/2:*「在前一個和下一個序列點之間,一個對象的儲值通過評估一個表達式最多修改一次。」* – sth 2010-07-19 02:37:04

+2

@sth:更精確地說,「序列點之間不止一個」。表達式可能包含一個序列點,在這種情況下,多次修改變量是可以的。例如,'&&','||'和逗號運算符都可以在單個表達式中形成順序點。 – 2010-07-19 02:41:42

+0

@sth:即使_更精確地說,這不是對編碼器的限制,而是對變量本身的限制。你的「不被允許......」的陳述並不完全正確。你被允許,這只是一個非常愚蠢的事情:-) – paxdiablo 2010-07-19 02:44:39

1

當你有:

a = b++; 

正在發生的事情是,b爲保存到與賦值是做B之後加一。所以,如果你這樣做:

x = x ++; 

和以前x爲10會發生什麼是10將被保存到x和後(之前你的printf完成)x由一個增加到11.這就是爲什麼打印11。

2

除了標準(因爲這個標準沒有定義),它的運行方式就是我期望的方式。

我的經驗法則是,對於具有x++一條線,你代替x++x並把x += 1以下行(或前行預增)。

按照經驗這條規則,你的代碼將被寫成

#include <stdio.h> 
int main() 
{ 
    int x = 10, y = 0; 
    x = x; // x: 10 
    x += 1; // x: 11 
    printf("x: %d\n", x); 
    y = x; // y: 11 
    x += 1; // x: 12 
    printf("y: %d\n", y); 
}