Operator pre inkrementacji - dziwny wynik

0
int x, i=1;
x = ++i + ++ i;
printf("%d", x);

nie rozumiem, czemu jako wynik wychodzi liczba 6, powinno być (i+1) + (i+1+1), czyli 5 - mógłby ktoś wytłumaczyć?

1

Masz dwie zmiany tej samej wartości w jednej instrukcji. To jest tak zwane UB.

0

Mógłbyś rozjaśnić? Bo wychodzi na to, że x=3+3, czyli tak jakby i zostało od razu zwiększone do 3. Dobrze myślę?

2

Nie. Standard języka nie definiuje w jakiej kolejności wykonają się tak zapisane operacje i tyle. Oznacza to że różne kompilatory C++ mogą dawać zupełnie inne wyniki. Nie wolno tak pisać i już.

0

Undefinied Behaviour. Takiej operacji nie można wykonać, bo dzieją sie rzeczy, ktore cięzko wytłumaczyć. Tak samo np funkcja nie-void, ktora nic nie zwraca. Musi cos zwraac, wiec jeśli kompilator to przepuści, a Ty wywołasz taką funckje, to nie wiadomo, co się stanie. Bardziej pobłażliwe kompilatory zrobią tak, zeby funckja zwracała losową wartość, ale to już zależy od kompilatora.

0

mhm, rozumiem. dziwną sprawą jest z kolei to, że dla każdego innego przykładu (i++ + ++i, i++ + i++, itd) daje wyniki zgodne z oczekiwaniami - ciekawe, czemu standard tego nie definuje. dzięki za odpowiedź

2

@kalwi
Hehe to jest faktycznie ciekawa sprawa.
Ogólnie sprowadza się to do tego, że gdyby standard wszystko definiował, to kompilator musiałby generować dużo więcej kodu maszynowego/asemblera w niektórych przypadkach, przez co wynikowy program byłby wolniejszy (ale dawałby zawsze zdefiniowane rezultaty). Powiedzmy, że dzięki temu, że standardy C/C++ pozostawia pewne rzeczy niezdefiniowane, programy napisane w tych językach są uznawane za "szybsze", niż te napisane we w pełni zdefiniowanych językach.

Dla przykładu:
Jedną z niezdefiniowanych operacji jest przepełnienie int'a (a więc int a = INT_MAX; a++;).
Gdyby standard mówił "w przypadku przepełnienia int'a ma lecieć exception", to na x86, kompilator by musiał dawać kod sprawdzający czy nastąpiło przepełnienie po każdej operacji arytmetycznej na intach. Oczywiście, jest to de facto jedna instrukcja w przypadku x86 (jno - jump if overflow flag is not set), ale w tych operacji w ciągu życia (działania) programu może być bardzo bardzo dużo, a więc spowolnienie mogłoby już być znaczne.
(Dodatkowo na starszych procesorach taki skok powodowałby wyczyszczenie pipeline'u/cache'u instrukcji, co boli dużo bardziej niż jedna instrukcja ;>)

Oczywiście istnieją języki w pełni zdefiniowane, w których kod, który napisałeś w pierwszym poście, nie są UB. Jeśli mnie pamięć nie myli przykładem będzie JavaScript, który przy każdym operandzie w standardzie ma DOKŁADNIE opisane jakie operacje mają miejsce i w jakiej kolejności się odbędą. Jeśli z ciekawości byś chciał to sprawdzić, to standard ECMAScript (na którym jest oparty JavaScript) znajdziesz tutaj: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262%20edition%205.1,%20June%202011.pdf

1 użytkowników online, w tym zalogowanych: 0, gości: 1