2011-12-20 20 views
59

Jestem trochę zdezorientowany tym, jak kompilator C# obsługuje przyrosty i dekrementy przed i po.C# konflikty przed i po inkrementacji

Kiedy kodować następujące:

int x = 4; 
x = x++ + ++x; 

x będzie miał wartość 10 później. Sądzę, że dzieje się tak dlatego, że pre-increment ustawia x na 5, co powoduje, że jest to 5+5, co oznacza . Wtedy post-inkrementacja zaktualizuje x do 6, ale ta wartość nie będzie używana, ponieważ wtedy 10 zostanie przypisana dozostanie przypisana do.

Ale gdy kod I:

int x = 4; 
x = x-- - --x; 

następnie x będzie 2 później. Czy ktoś może wyjaśnić, dlaczego tak się dzieje?

+2

Świetne pytanie! I nauczyliśmy się nigdy pisać kodu, trzeba myśleć o tym, co może zrobić, ale co by to zrobiło. – RvdK

+15

Każdy, kto pisze taki kod, powinien zostać zabity i postrzelony. Nie ma żadnego usprawiedliwienia dla 'x = x ++ + ++ x;' ... ever. –

+15

to było tylko pytanie "akademickie" - nigdy nie pisałbym też kodu :-) – Schweder

Odpowiedz

46

x-- będzie 4, ale będzie 3 w momencie --x, więc będzie to koniec jest 2, to musisz

x = 4 - 2 

btw, pierwszym przypadku będzie x = 4 + 6

Oto mały przykład, który wydrukuje wartości dla każdej części, być może w ten sposób zrozumiesz to lepiej:

static void Main(string[] args) 
{ 
    int x = 4; 
    Console.WriteLine("x++: {0}", x++); //after this statement x = 5 
    Console.WriteLine("++x: {0}", ++x); 

    int y = 4; 
    Console.WriteLine("y--: {0}", y--); //after this statement y = 3 
    Console.WriteLine("--y: {0}", --y); 

    Console.ReadKey(); 
} 

to drukuje o ut

x++: 4 
++x: 6 
y--: 4 
--y: 2 
+3

Dziękuję za odpowiedź - myślałem, że przyrosty post- i pre-są wykonywane po/przed oceną kompletnego codeline - ale są wykonywane po/przed oceną każdego elementu w wyrażeniu. – Schweder

+0

@Schweder, drobna korekta: operatory są wykonywane po/przed oceną zmiennej, do której zostały zastosowane. Nie każdy termin w wyrażeniu. – Amy

+2

@Inuyasha: Korekta Twojej korekty: operatory są * zawsze * wykonywane * po * ocenie zmiennej jako zmiennej. Różnica między operatorami przed i po to tylko * wartość zwrócona *, a nie * kolejność, w której wykonywane są operacje *. –

-1

Myślę, że wyjaśnienie ++ + ++ przypadku jest źle:

komenda ........... wartość x

.... .............. zdefiniowana

Int x = 4 .......... 4

x ++ ........... .... 5 (pierwszy tydzień to 4)

++ ............... 6 x (drugi do składnika wynosi 6)

X = summand1 + summand2 ..4 + 6 = 10

Analogicznie wytłumaczenie - - - obudowa

polecenie ........... wartość x

.................. nieokreślone

Int x = 4 .......... 4

x --............... 3 (subtactor jest 4)

--x ............... 2 (odjemnik jest 2)

X = odejmujący-odjemnik ..4-2 = 10

+0

Nie zrozumiałem, że w ogóle odpowiadasz, przepraszam. –

+0

@phresnel Poprawiłem kilka błędów w odpowiedzi. Zasadniczo mówi to samo, co odpowiedź, którą przyjąłeś: w rzeczywistości dostajemy 10, ponieważ dodajemy 4 i 6; 2 to różnica między 4 a 2. – phoog

16

Pozwala spojrzeć na IL który pobiera generowane z tym stwierdzeniem

IL_0002: ldloc.0  

Ładunki wartość x na stos. Stack => (4)

IL_0003: dup   

Powielenie najwyższego przedmiotu na stosie. Stos => (4, 4)

IL_0004: ldc.i4.1  

Wepchnij 1 na stos. Stos => (1, 4, 4)

IL_0005: sub   

Odejmij dwie najwyższe wartości i wypchnij wynik na stos. Stos => (3, 4)

IL_0006: stloc.0  

Przechowaj najwyższą wartość stosu z powrotem na x. Stos => (4)

IL_0007: ldloc.0  

Załaduj wartość x z powrotem do stosu. Stos => (3, 4)

IL_0008: ldc.i4.1  

Załaduj wartość 1 na stos. Stos => (1, 3, 4)

IL_0009: sub   

Odejmij dwa. Stos => (2, 4)

IL_000A: dup   

Powielanie górna wartość => (2, 2, 4)

IL_000B: stloc.0  

sklepu górna wartość na X. Stos => (2, 4)

IL_000C: sub  

Odejmij dwie najwyższe wartości. Stos => (2)

IL_000D: stloc.0 

Zapisz ponownie tę wartość na x. x == 2

2

W tym przykładzie

int x = 4; 
x = x++ + ++x; 

można złamać to lubią:

x = 4++; which is = 5 
x = 4 + ++5; which is 4 + 6 
x = 10 

Podobnie

int x = 4; 
x = x-- - --x; 

Tutaj

x = 4--; which is = 3 
x = 4 - --3; which is 4 - 2 
x = 2 

Po prostu możesz powiedzieć, zastąp aktualną wartość x, ale za każde ++ lub - dodaj/odejmij wartość od x.

6

Najciekawsza rzecz, że otrzymasz zupełnie inną odpowiedź z C++. Kompilator Net.

int x = 4; 
x = x++ + ++x; // x = 11 
x = 4; 
x = x-- - --x; // x = -1 

Oczywiście różnica w wynikach jest określana przez różne semantyki - wydaje się normalne. Jednak pomimo zrozumienia faktu, że dwa kompilatory .net nie zachowują się w podobny sposób w przypadku takich podstawowych rzeczy, również mnie to dezorientuje.

+2

W C++ (nie jest to jedna z wersji C++ w C++ innych niż C++), modyfikowanie zmiennej wiele razy przed zakończeniem pełnego wyrażenia daje niezdefiniowane zachowanie. –

+4

Nie ma to nic wspólnego z * parse *. Ma to związek z różnymi dozwolonymi semantycznymi językami dwóch języków dotyczącymi punktów sekwencji. –

8

Z Twojego komentarza:

Myślałem, że post- i pre-przyrosty są wykonywane po/przed oceną całkowitego codeline - ale są one wykonywane po/przed oceną każdego elementu w wyrażeniu.

Twoje nieporozumienie jest niezwykle powszechne. Zauważ, że w niektórych językach, takich jak C, nie określa się, kiedy efekt uboczny staje się widoczny i dlatego jest legalny, ale nie wymagany, aby twoje oświadczenie było prawdziwe w C.

Tak nie jest w C#; w języku C# skutki uboczne kodu po lewej stronie wyrażenia są zawsze obserwuje się zdarzyć przed kodem z prawej strony wykonuje (z pojedynczej nici; w wielowątkowych scenariuszy wszystkie zakłady są wyłączone.)

Dla bardziej szczegółowej wyjaśnienie jakie operatory inkrementacji zrobić w C#, zobacz:

What is the difference between i++ and ++i?

Istnieje bardzo wiele dodatkowe linki do artykułów tam mam napisane na ten temat często niezrozumiany.

Powiązane problemy