2011-07-16 12 views
27

Możliwe duplikaty:
Why does this go into an infinite loop?i = i ++ nie zwiększa wartości. Czemu?

Rzeczy takie jak i = i++ mieć niezdefiniowanej zachowanie w C i C++, ponieważ wartość skalarnym obiektu wynosi zmiany dwa razy w tej samej wypowiedzi bez interwencji punkt sekwencji.

Jednak przypuszczam, że tego rodzaju wyrażenia mają dobrze zdefiniowane zachowanie w C# lub Java, ponieważ AFAIK ocena argumentu idzie od lewej do prawej i są punkty sekwencji na całym.

To powiedziawszy, spodziewam się, że i = i++ będzie odpowiednikiem i++. Ale nie jest. Poniższy program wyprowadza 0.

using System; 
class Program 
{ 
    static void Main(string[] args) 
    { 
     int i = 0; 
     i = i++; 
     Console.WriteLine(i); 
    } 
} 

Czy możesz mi pomóc zrozumieć, dlaczego?

Zastrzeżenie: Jestem w pełni świadomy, że czy zachowanie powyższych konstruktów jest zdefiniowany, są głupie, bezużyteczny, nieczytelny, niepotrzebne i nie powinny być używane w kodzie. Jestem po prostu ciekaw.

+6

@Dvvovator: Chcesz zostawic komentarz? –

+1

Zazwyczaj nie :) – Tigran

+5

ten został zapytany w ubiegłym roku o Javie, ale odpowiedział w języku C# (oba działają podobnie do tego przypadku): http://stackoverflow.com/questions/3831341/why-does-this-go- pętla w nieskończoność – BoltClock

Odpowiedz

38

zachowanie jest dobrze zdefiniowane w C# i kolejność oceny jest:

  1. Lewa strona i ocenia zmiennej i
  2. prawej stronie jest oceniana na 0, a i jest zwiększany (obecnie i==1)
  3. zadanie jest realizowane, ustawia i 0. (obecnie i==0)

Końcowy wynik to i==0.

Generalnie najpierw utworzyć drzewa wyrażenie. Aby to ocenić, najpierw oceniaj lewą stronę, potem prawą stronę, a na końcu operację w katalogu głównym. Rób to rekurencyjnie.

+0

Ah! To ma sens. Jestem głupi :) –

+3

W Javie można czasami zaobserwować wartość '1' z równoległego wątku, jeśli zrobisz' i' volatile (w moim teście typowo 65 razy w 100 milionach iteracji). – starblue

+1

i = ++ powinien również działać dobrze. – arkoak

17

Wynik wyrażenia po inkrementacji i++ jest oryginalną wartością i. Po ocenieniu i++ (zwiększając i) przypisujesz starą wartość i do ... i.

Wystarczy użyć

i++; 

;)

+1

byłem świadomy różnicy preincrement i postincrement. Byłem zdezorientowany, bo spodziewali się efekt uboczny przyrostu nastąpić po ocenie całego wyrazu ... Oczywiście myliłem –

+0

@Armen tak, C# jest dość dużo lewej do prawej –

+3

@Marc znajdę preparat że wyrażenie jest oceniane od lewej do prawej mylące. Wolę myśleć o wyrażeniu jako drzewie, które jest następnie rekurencyjnie oceniane. I każdy węzeł najpierw ocenia swoje argumenty od lewej do prawej i ostatecznie wykonuje samą siebie. – CodesInChaos

3

Dobrze, wyrażenie po prawej stronie musi być oceniana przed przypisaniem może mieć miejsce. Teraz i++ oceni aktualną wartość i, a wartość i zwiększy się o jeden. Jednak przypisanie nie zostało jeszcze wykonane, a jeśli tak jest, nadpisze bieżącą wartość i (1) bez względu na wyrażone wyrażenie rhs, które w twoim przypadku wynosi 0.

Kluczową różnicą jest pomiędzy ++i (preinkrementacja, która zwraca wartość nowy z ipo przyrostu wartości) i i++ lub postinkrementacja, co ocenia się na bieżącej wartości iprzed przyrostu wartości.

Gdyby użyto ++i zamiast wyrażenie po prawej stronie byłaby oceniana na 1, co skutkuje í == 1.

15

i = ++i jest kod, który robi to, co myślisz, że dzieje się tutaj. i++ faktycznie zachowuje się nieco inaczej.

Z i++ wartość i jest zwiększona, ale wartość i++ nie jest nowa wartość i, to poprzednia wartość.Więc kiedy robisz i = i++, mówisz "zwiększ wartość i, następnie ustaw i na starą wartość".

+5

ponownie pierwsza linia; po prostu 'i ++;' będzie "kodem, którego szuka" –

+3

Nie sądzę, że szuka jakiegoś kodu, ale on szuka lepszego zrozumienia języka C#. W szczególności, w których następują efekty porządkowe zamówień i jak zachowuje się wynik wielu przypisań do tej samej zmiennej w wyrażeniu. – CodesInChaos

+1

@Marc: Z wyjątkiem tego, że nie szukam żadnego kodu :) –

Powiązane problemy