Tytułową zagadkę dostałem od furia i uznałem na tyle ciekawą, że przez kilka kolejnych dni rozdawałem ją na prawo i lewo. Zagadka jest o tyle ciekawa, że są tam dwa Undefined Behaviour w jednej krótkiej linii. Obecność UB powoduje oczywiście, że nie ma jednej dobrej odpowiedzi; odpowiedzi tak naprawdę są trzy: 11, 12 lub 13.

Zacznę od rozważań nad potencjalnymi rozwiązaniami, a potem przejdę do wyników empirycznych (które przygotował nism0).

Więc... które miejsca są UB/niewiadome/zależne od kompilatora?

Po pierwsze, nie wiadomo które a zostanie podstawione pierwsze w równaniu z drugiego polecenia (przez podstawienie mam na myśli skopiowanie wartości z pamięci do jakiegoś podręcznego rejestru). Opcje są dwie:

Opcja 1. Najpierw podstawienie pierwszego a, potem wyliczenie pre-inkrementacji i podstawienie drugiego a (post-inkrementację na chwilę pominę):
a = a + ++a;

Krok 1. Podstawienie pierwszego a.
a = 5 + ++a; (a==5)

Krok 2. Pre-inkrementacja a.
a = 5 + a;   (a==6)

Krok 3. Podstawienie drugiego a.
a = 5 + 6;   (a==6)

Krok 4. Wyliczenie dodawania.
a = 11;

Opcja 2. Najpierw wykonana zostanie pre-inkrementacja, łącznie z zapisem wyniku do pamięci, a dopiero później nastąpi podstawienie pierwszego a.
a = a + ++a;

Krok 1. Pre-inkrementacja a.
a = a + a;   (a==6)

Krok 2 i 3. Podstawienie pierwszego i drugiego a.
a = 6 + 6;   (a==6)

Krok 4. Wyliczenie dodawania.
a = 12;

Czyli już z samej pre-inkrementacji i podstawiania dostajemy dwa różne wyniki (11 i 12).

Drugi UB związany jest z post-inkrementacją i potencjalnie trywialną linijką a = a++. Jak się okazuje, są tutaj również dwie opcje, które rozważę posługując się kodem pomocniczym w postaci int a = 5; a = a++;.

Terminologia:
a_mem - a w pamięci (np. jako lokalna zmienna na stosie)
a_copy - kopia a w jakimś podręcznym rejestrze

Opcja 1. Wynikowy kod ma następującą formę (w pseudo-assembly):
Warunki początkowe: (a_mem == 5, a_copy == brak)

Krop 1. Podstawienie a do równania.
a = 5++; (a_mem == 5, a_copy == 5)

Krok 2. Post-inkrementacja na zmiennej w pamięci.
a = 5;   (a_mem == 6, a_copy == 5)

Krok 3. Przypisanie, czyli a_copy leci do a_mem.
(a_mem == 5, a_copy == brak)

W powyższym wypadku wynik post-inkrementacji a zaginął w akcji. Tj. niby zostało zapisane do pamięci, ale po chwili operacja przypisania (=) wrzuciła finalny wynik obliczeń (czyli 5) do zmiennej a w pamięci nadpisując jednocześnie wynik post-inkrementacji. (prawdę mówiąc zawsze uważałem, że operacja post-inkrementacji jest deferowana na sam koniec wszystkich obliczeń, więc uznałbym to zachowanie za bug kompilatora)

Opcja 2. Post-inkrementacja dzieje się po przypisaniu.
Warunki początkowe: (a_mem == 5, a_copy == brak)

Krop 1. Podstawienie a do równania.
a = 5++; (a_mem == 5, a_copy == 5)

Krok 3. Przypisanie, czyli a_copy leci do a_mem.
(zostaje a++) (a_mem == 5, a_copy == brak)

Krok 2. Post-inkrementacja na zmiennej w pamięci.
(a_mem == 6, a_copy == brak)

Czyli post-inkrementacja zostaje faktycznie zdeferowana na koniec obliczeń.

Podsumowując, ostateczny wynik a = a++ + ++a to:
Opcja 1 i 1: 5+6 i wynik post-inkrementacji MIA, razem 11
Opcja 2 i 1: 6+6 i wynik post-inkrementacji MIA, razem 12
Opcja 1 i 2: 5+6 i post-inkrementacja zdeferowana, razem 12
Opcja 2 i 2: 6+6 i post-inkrementacja zdeferowana, razem 13

Jak wspomniałem na początku, nism0 porobił trochę testów (empirycznych), z czego wyszła następująca tabelka (update: jak słusznie zauważył nonek, kolumny 1 i 2 oraz 4 z 5 w tabeli były zamienione miejscami względem wyników; teraz już jest OK, thx nonek ;>) (update 2: jeszcze jedna seria literówek poprawiona (dot. C#), thx qyon):

Kod1 Kod 2 Kod 3 Kod 4 Kod 5 Kod 6
int a = 5;
a = a++ + a++;
int a = 5;
a = a++ + ++a
int a = 5;
a = ++a + a++;
int a = 5;
a = ++a + ++a;
int a = 5;
a = a++;
int a = 5;
a = a + ++a;

                           
Kompilator/Język Wersjawynik 1 wynik 2 wynik 3 wynik 4 wynik 5 wynik 6
gcc 2.9512 13 14 13 6 12
gcc 4.112 13 1413 6 12
gcc 4.212 13 1413 6 12
gcc 4.2.1 Apple 12 13 14 13 6 12
gcc 4.312 13 1413 6 12
gcc 4.3.3 12 13 13 14 6 12
gcc 4.4.4 12 13 13 14 6 12
gcc 4.6.0 (exp.) 12 13 14 13 6 12
gcc 4.5.1 MinGW64 12 13 13 14 6 12
tcc 0.9.25?? ?? ?? ?? 5 12
bcc 0.16.17?? ?? ?? ?? 5 12
Microsoft C/C++ 16.00.30319.01 (80x86)12 13 13 14 6 12
Embarcadero C++ 6.31 for Win32 12 13 13 14 6 12
Intel C++ 12.0.1.127 12 13 13 13 6 12
Keil C 9.02 11 12 12 13 6 12
SDCC 3.0.1 #6092 11 12 13 14 5 12
clang 2.8 11 12 12 13 5 11
clang 1.6 Apple 11 12 12 13 5 11
PHP 5.2.10 11 12 12 13 5 12
java 1.6.0_06 11 12 12 13 5 11
javac 1.4.2_12 11 12 12 13 5 11
java 1.6.0_21 11 12 12 13 5 11
javac 1.6.0_22 11 12 12 13 5 11
C# 2.0 11 12 12 13 5 11
C# 4.0 11 12 12 13 5 11
C# Mono 2.6.4 11 12 12 13 5 11
Borland Turbo C++ for DOS 2.01 12 13 13 14 6 12
HiSoft C for ZX Spectrum 1.3 11 12 12 13 5 12

Podziękowania za dodatkowe wyniki dla: Icewall, Krzysztof Kotowicz (za PHP 5.2.10), mlen (za 2x clang, 2x gcc), none'a (za 2xJava), Keraj (za 2x Java), MDobak (za SDCC i Keil C), garbaty_lamer (za 3xC#, Turbo C++, HiSoft C), Xgrzyb90 (za gcc 4.4.4), no_name (za gcc 4.3.3), dikamilo (za mingw64 4.5.1)

Update: kapitalny screen z HiSoft C for ZX Spectrum który garbaty lamer wrzucił w komentarzach:

HiSoft C for ZX Spectrum, screen by garbaty lamer

Wyniki z innych kompilatorów jak zwykle mile widziane (kod do testów, autorstwa nism0, umieściłem poniżej). Wyniki z innych języków programowania posiadających pre- i post-inkrementacje również mogą być ciekawe.

I tyle na dzisiaj. Szczęśliwego nowego roku ;>

Update:
P.S. Zachęcam do rzucenia okiem na komentarze, szczególnie na komentarz Rolek'a (Rolka? ;>), który zaproponował test (kod jest w jego komentarzu) z przeciążeniem operatorów (wyniki by Rolek (MSVC++) & me (g++)):
Kod1 Kod 2 Kod 3 Kod 4 Kod 5 Kod 6
int a = 5;
a = a++ + a++;
int a = 5;
a = a++ + ++a
int a = 5;
a = ++a + a++;
int a = 5;
a = ++a + ++a;
int a = 5;
a = a++;
int a = 5;
a = a + ++a;

     
Kompilator/Język Wersjawynik 1 wynik 2 wynik 3 wynik 4 wynik 5 wynik 6
Microsoft C/C/++ (bez przeciążenia) 16.00.30319.01 12 13 13 14 6 12
Microsoft C/C/++ (z przeciążeniem) 16.00.30319.01 11 13 12 14 5 12
g++ (bez przeciążenia) 4.5.0 MinGW 12 13 13 14 6 12
g++ (z przeciążeniem) 4.5.0 MinGW 11 13 12 14 5 12


Poza tym, krlm rzucił dobry link o sequence points: http://en.wikipedia.org/wiki/Sequence_point.

Komentarz garbatego_lamera dot C# jest również ciekawy i warty uwagi:
Nudne to wklejanie takich samych wyników. To, co w niektórych językach jest undefined, w innych jest perfectly defined. Cytat z §7.3 specyfikacji:
Operands in an expression are evaluated from left to right. For example, in F(i) + G(i++) * H(i), method F is called using the old value of i, then method G is called with the old value of i, and, finally, method H is called with the new value of i. This is separate from and unrelated to operator precedence.


End of update.

Oryginalny kod do testów:
#include <stdio.h>

int main(void)
{
 int a = 5, b = 5, c = 5, d = 5, e = 5, f = 5;

 // test pierwszy
 a = a++ + a++;
 printf("%i \n",a);

 // test drugi
 b = b++ + ++b;
 printf("%i \n",b);

 // test trzeci
 c = ++c + c++;
 printf("%i \n",c);

 // test czwarty
 d = ++d + ++d;
 printf("%i \n",d);

 // test piaty
 e = e++;
 printf("%i \n",e);

 // test szosty
 f = f + ++f;
 printf("%i \n",f);

 // koniec testow
 return 0;
}


Appendix 4:
Komentarz by Cem Paya (ad Java0:
--start--
Similar to C#, this is also not a riddle for Java because Java defines
evaluation to be strictly left-to-right.
See section 15.7 here for some examples with side-effects as in your case:
http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html
In C++ where it is undefined, the result can also depend on the
optimization level used during compilation, which can change the
number of times a value is referenced. eg the compiler expects "a" to
not change its value during the evaluation and may optimize other
occurences to the same one it fetched.

==end==

Comments:

2011-01-03 09:58:30 = krlm
{
Z całym szacunkiem do wlozonej pracy ale obliczanie wyrazen, ktore sa UB nie ma najmniejszego sensu. Potem powstaja takie dziwolagi jak tutaj: http://42.pl/u/2x9y (polecam przeczytac caly watek). Warto pamietac, ze po wystapieniu jednego UB, kazda nastepna instrukcja jest niezdefiniowana. (Odnoszac sie do powyzszego, co z innymi architekturami - popularnym ARM, albo Objective-C ...itd.?). Rozumiem, ze to for fun - ale mozna lepiej spozytkowac swoje moce :) Pozdrawiam.
}
2011-01-03 10:01:56 = Krzysztof Kotowicz
{
Wyniki z PHP (5.2.10.dfsg.1-2ubuntu6.5):

11,12,12,13,5,12
}
2011-01-03 10:25:35 = mlen
{
Wyniki:

clang version 2.8 (branches/release_28)
11
12
12
13
5
11


Apple clang version 1.6 (tags/Apple/clang-70)
11
12
12
13
5
11

gcc version 4.2.1 (Apple Inc. build 5664)
12
13
13
14
6
12

gcc version 4.6.0 20101106 (experimental) (GCC)
12
13
13
14
6
12
}
2011-01-03 11:20:48 = no_name
{
gcc (GCC) 4.3.3

12
13
13
14
6
12
}
2011-01-03 11:37:42 = dikamilo
{
mingw64 gcc version 4.5.1 (tdm64-1)

12
13
13
14
6
12
}
2011-01-03 14:29:42 = .Dexter.
{
Coś takiego już zostało opracowane:
http://nism0.lunarii.org/dump/testy.html
}
2011-01-03 14:31:07 = .Dexter.
{
Oops, nie doczytałem,
przepraszam :D
}
2011-01-03 14:43:12 = none
{
java 1.6.0_06
11
12
12
13
5
11
}
2011-01-03 15:47:28 = Keraj
{
javac 1.4.2_12
12
11
13
12
5
11

javac 1.6.0_22
12
11
13
12
5
11

Wątpię, by to się w międzyczasie zmieniało.
}
2011-01-03 16:54:47 = Radom
{
Akurat wczoraj zacząłem czytać "Pasję C++" Grębosza gdzie autor wyjaśnia podobne zagadnienie na przykładzie makrodefinicji. Grębosz pisze, że wszystko zależy od kompilatora co zresztą widać na testach. Jako przestrogę daje jeszcze ciekawsze wyrażenie
((a++) + a) * (a++) * (a++) / (a++)

Pozdrawiam
}
2011-01-03 17:12:09 = none
{
u mnie (WinXP32) 1.6.0_21 daje rowniez wynik:
11
12
12
13
5
11
wiec miedzy wersjami mi sie nic nie zmienia ;). Ale nie jestem specjalista java wiec moze mam blad w kodzie.
}
2011-01-03 17:14:51 = Keraj
{
Ups, zagalopowałem się, nie zauważyłem, że kod do testów jest inny niż ten w tabelce powyżej. Sunowa/Oraclowa Java tak samo w starej jak i nowej:
11
12
12
13
5
11
}
2011-01-03 18:07:14 = Rolek
{
Jeśli opakujemy inta w klasę to wyniki też są trochę inne :D
[code]
#include <cstdio>

class Int
{
int m_val;
public:
Int(const int val = 0) : m_val(val) {}
Int(const Int& o) : m_val(o.m_val) {}
operator int() const { return m_val; }
Int& operator = (const Int& o) { m_val = o.m_val; return *this; }
Int& operator ++ () { ++m_val; return *this; }
Int operator ++ (int) { Int t = *this; ++*this; return t; }
Int operator + (const Int& r) const { return m_val + r.m_val; }
};

template<typename T> void foo(void)
{
T a = 5, b = 5, c = 5, d = 5, e = 5, f = 5;

// test pierwszy
a = a++ + a++;
printf("%i ",(int)a);

// test drugi
b = b++ + ++b;
printf("%i ",(int)b);

// test trzeci
c = ++c + c++;
printf("%i ",(int)c);

// test czwarty
d = ++d + ++d;
printf("%i ",(int)d);

// test piaty
e = e++;
printf("%i ",(int)e);

// test szosty
f = f + ++f;
printf("%i ",(int)f);

}

int main()
{
printf("
int: "); foo<int>();
printf("
Int: "); foo<Int>();
return 0;
}
[/code]

Wyniki:
int: 12 13 13 14 6 12
Int: 11 13 12 14 5 12

IDE: MsVC++2010EE
Kompilator: Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86

Może ktoś sprawdzi jakie wyniki daje np. g++ albo coś innego?
}
2011-01-03 19:05:35 = garbaty lamer
{
C# 4.0 (testowane przy pomocy LinqPad 4.31)
11
12
12
13
5
11

C# 2.0 (testowane przy pomocy LinqPad 2.31)
11
12
12
13
5
11

C#/Mono 2.6.4 (Linux/x86)
11
12
12
13
5
11

Nudne to wklejanie takich samych wyników. To, co w niektórych językach jest undefined, w innych jest perfectly defined. Cytat z §7.3 specyfikacji:
Operands in an expression are evaluated from left to right. For example, in F(i) + G(i++) * H(i), method F is called using the old value of i, then method G is called with the old value of i, and, finally, method H is called with the new value of i. This is separate from and unrelated to operator precedence.

HNY!
}
2011-01-03 20:22:16 = Nikow
{
int a = 5;
a = a++ + ++a;
a == 6+6+1 == 13
ponieważ:
C ma cos takiego jak wagi operatorow.
Wedlug nic pierw bedzie POSTINKREMENTACJA (a++),
dopiero pozniej bedzie PREINKREMENTACJA (++a),
następnie dodawanie.
jednakze POSTINKREMENTACJA jest liczona dopiero po ; dlatego też mamy
6 (++5) + 6 (drugi operator już preinkrementowany, więc jest wstawiana preinkrementowana wartosc z czlonu pierwszego) +1 (efekt postinkrementacji).
6+6+1=13. ;)
Mam nadzieje że nie zagmatwałem za bardzo.
Ktos na lekcjach z C i Operatorów nie uważał.

http://staff.elka.pw.edu.pl/~jarabas/dyd/prm/operatory.pdf
http://nadzieja.el-kfa.net/strony/operators.html
http://pl.wikibooks.org/wiki/C/Operatory#Priorytety_i_kolejno.C5.9B.C4.87_oblicze.C5.84
}
2011-01-03 20:44:11 = krlm
{
@Nikow: C/C++ ma tez cos co zwie sie sequence point. Proponuje poczytac: http://en.wikipedia.org/wiki/Sequence_point
}
2011-01-04 10:03:17 = nonek
{
Chyba jest błąd w tabeli ? Kolumny "Wynik 1" oraz Wynik 2" powinny być zamienione między sobą.
Wyniki dla gcc version 4.1.2 20080704 (Red Hat 4.1.2-48:
Wynik2 | Wynik1 | Wynik 3 | Wynik 4 | Wynik 5 | Wynik 6
12 | 13 | 13 | 14 | 6 | 12

Na dalsze kolumny nie patrzałem, więc nie wiem czy jest błąd, ale napewno w kolumny 1 i 2 są zamienione miejscami
}
2011-01-04 19:13:01 = Xgrzyb90
{
tomasz@darkstar:~/tmp$ gcc -v
Reading specs from /usr/lib/gcc/i486-slackware-linux/4.4.4/specs
Target: i486-slackware-linux
Configured with: ../gcc-4.4.4/configure --prefix=/usr --libdir=/usr/lib --enable-shared --enable-bootstrap --enable-languages=ada,c,c++,fortran,java,objc --enable-threads=posix --enable-checking=release --with-system-zlib --with-python-dir=/lib/python2.6/site-packages --disable-libunwind-exceptions --enable-__cxa_atexit --enable-libssp --with-gnu-ld --verbose --with-arch=i486 --target=i486-slackware-linux --build=i486-slackware-linux --host=i486-slackware-linux
Thread model: posix
gcc version 4.4.4 (GCC)
tomasz@darkstar:~/tmp$ gcc -o test test.c
tomasz@darkstar:~/tmp$ chmod +x test
tomasz@darkstar:~/tmp$ ./test
12
13
13
14
6
12
}
2011-01-04 19:44:02 = MDobak
{
To ja podrzucę wyniki nieco nietypowych kompilatorów :)
SDCC 3.0.1 #6092
11
12
13
14
5
12
Keil C 9.02
11
12
12
13
6
12
}
2011-01-04 21:10:42 = Nism0
{
Hi.

Tak się zastanawiam (i tutaj pytanie/prośba) czy mógłbym uzupełnić tabelkę o wasze wyniki (mam na myśli wyniki kompilatorów C/C++) ?

PS: Sam się zastanawiam czy by nie zrobić kilku testów dla innych języków.
}
2011-01-04 21:59:04 = krlm
{
@Nism0 - a co jest takiego szczegolnego w tych UB-wyrazeniach, ze akurat te chcesz gromadzic/spisywac? Pozdrawiam.
}
2011-01-05 08:26:14 = Nism0
{
@krlm :

Szczególnego ? Raczej nic (chociaż zależy dla kogo), ale zawsze się może przydać taki drobny spis. BTW nie mam zamiaru tego kontynuować w nieskończoność, raczej się skupiam na C/C++. Najbardziej tutaj zainteresowały mnie wyniki podane przez @MDobak, bo są to nietypowe kompilatory.
}
2011-01-05 13:09:27 = @MDobak
{
@Nism0
A używaj tych wyników do czego chcesz :).
}
2011-01-05 15:33:50 = Nism0
{
Jedynie do celów edukacyjnych :D Thx btw ;)
}
2011-01-07 09:22:29 = Gynvael Coldwind
{
Primo, dziękuje wszystkim za wyniki! Wrzuciłem je do tabelki (z podziękowaniami ofc).

@krlm
Sens jest prosty - wskazać, że coś takiego istnieje. Poza tym przyznaję, że ciekawi mnie jak który kompilator podchodzi do kompilacji, a z wyliczania UB można coś takiego próbować wnioskować.
Ad "co z innymi architekturami": wszelkie wyniki z innych architektur również mile widziane ;)
Ad link - thx, ciekawy ;>
Ad "lepsze spożytkowanie swoich mocy" - hehe przypuszczam również, że można lepiej spożytkować swoje moce, niż użycie ich by wytykać innym subiektywnie gorsze spożytkowanie mocy ;)

@Radom
Fajne wyrażenie :)
W drafcie n1336 standardu C99 pojawiają się dwa inne przykłady na UB z sequencami:
i = ++i + 1;
a[i++] = i;
Ten pierwszy jest imo dość ciekawy.

Pojawia się także:
EXAMPLE In the function call
(*pf[f1()]) (f2(), f3() + f4())
the functions f1, f2, f3, and f4 may be called in any order. All side effects have to be completed before
the function pointed to by pf[f1()] is called.

@nonek
Thx, fixed.

@Nikow
Trochę źle rozumiesz wagi operatorów (mają one znaczenie przy wyborze które z danych dwóch operacji wykonać najpierw, a nie przy wyborze co ma się wykonać pierwsze globalnie dla całego wyrażenia).
Rzuć okiem na link krlm'a.

}
2011-01-14 01:31:35 = garbaty lamer
{
Pociągnijmy to dalej!
Borland (obecnie Embarcadero) Turbo C++ 2.01 for DOS: 12, 13, 13, 14, 6, 12
HiSoft C 1.3 for ZX Spectrum (8 bit FTW!): 11, 12, 12, 13, 5, 12
(http://img94.imageshack.us/img94/7498/hisoftgynvael.png)
pozostałe emulatory (Amstrad, Amiga) i wirtualki (Solaris) niestety zdechły...
}
2011-01-14 17:58:12 = Gynvael Coldwind
{
@garbaty lamer
Woah, ale klasyki wyciągnąłeś ;)
Update wrzucony. Screen pozwoliłem sobie przerzucić na mój serwer i dodać do artykułu ;>
}
2011-01-16 12:23:06 = garbaty lamer
{
Proszę bardzo ;-)

O ile tabela jest ciekawa, to prezentowane w niej wyniki nie powinny być w żadnym wypadku użyte do przewidywania zachowania konkretnego kompilatora. Jestem przekonany (choć nie mam jeszcze dowodów), że wyniki mogą różnić się w zależności od użytych opcji optymalizacji, lub nawet od konkretnego kodu. Specyfikacja definiuje to niezdefiniowane zachowanie, sprawdziłem dla ANSI C, dla C++ sprzed standaryzacji oraz ANSI/ISO C++. Nie wiem czy ze względu na copyright mogę podać treść, na wszelki wypadek nie podam, odsyłam do
- B. Kerninghan i D. Ritchie, "Język ANSI C", p. A7 "Wyrażenia",
- B. Stroustrup "Język C++" (o języku sprzed standaryzacji), p. 14.5 "Wyrażenia",
- dokument ISO/IEC 14882:2003 - rozdział 5 "Expressions", akapit 4.

A oto kilka ciekawostek, na podstawie przykładów podanych w w/w publikacjach:
a = 0;
a = tablica[a++]; // zachowanie jest niezdefiniowane

b = 13, b++, b++; // zachowanie zdefiniowane, b otrzymuje wartość 15

c = 0;
c = ++c + 1; // zachowanie jest niezdefiniowane
}
2011-01-17 15:59:05 = Flink
{
stestujcie również dwa literały napisowe
"gynvael" L"coldwind"
Przypominam również programistom, że program którego zachowanie nie jest zdefinowane jest nieprzenośny.
}
2011-02-08 09:04:32 = Reg
{
Ciekawe. Ale moim zdaniem to jest porażka C++, że takie UB występują w standardzie. I mean, rozumiem, że dzięki niezdefiniowaniu z góry wyników takich dziwnych operacji kompilator może sobie pozwolić na więcej optymalizacji, ale jak dla mnie operatorów ++a i a++ mogłoby w ogóle nie być. Sam ich używam, jak każdy programista C++, jednak nie podoba mi się cała ta idea inkrementowania zmiennej "przy okazji" wyliczania innego wyrażenia. Inne języki programowania tego nie mają (Python, Pascal) i odchodzą wtedy całkowicie problemy takie jak tu opisany.
}
2011-02-10 11:23:30 = hazy77
{
ja dorzucę perla v5.10.1
11
12
13
14
5
12
}
2011-03-10 16:03:10 = jacek
{
Robiłem testy na palach i mi wyszło za każdym razem
12 (ilość palcy u rąk - 10).
}
2011-03-14 19:45:45 = nazriel
{
Dla D 2.0
gcc version 4.5.2 20101216 (gdc hg, using dmd 2.052) (GCC)

naz@quad ~/D $ ./test
12
13
13
14
6
}
2012-09-24 19:38:42 = eider
{
Pawn compiler 3.2.3664

11
12
12
13
5
11
}
2012-09-25 10:55:46 = eider
{
gcc (GCC) 3.4.2 (mingw-special)

12
13
13
14
5
12

------

g++ (GCC) 3.4.2 (mingw-special)

12
13
13
14
5
12
}
2015-10-07 10:04:39 = event15
{
Ja podrzucę tylko PHP:
Output for 5.1.0 - 7.0.0rc4, hhvm-3.6.1 - 3.9.1
11
12
12
13
5
12

-----------------------

Output for 4.3.0 - 5.0.5
11
12
12
13
5
11

Sprawdzone zostały praktycznie wszystkie wersje PHP od 4.3.0 jakie zostały wydane.
}
2017-06-15 20:15:01 = Darkstar
{
Fajnie że zwróciłeś na to uwagę. To są takie małe smaczki, które potrafią przyprawić o niezły ból głowy.
}
2018-11-11 11:43:06 = bl4de
{
Cześć Gyn,

Trochę odgrzewam kotleta, ale wspomniałeś ten post w swojej książce w rozdziale 4., i postanowiłem sprawdzić :)

Wyniki dla Apple LLVM version 10.0.0 (clang-1000.11.45.5):

11
12
12
13
5
11
}
2022-11-16 21:01:41 = Jacek
{
JS
var a = 5; a = a++ + a++
11
var a = 5; a = a++ + ++a
12
var a = 5; a = ++a + a++
12
var a = 5; a = ++a + ++a
13
}

Add a comment:

Nick:
URL (optional):
Math captcha: 9 ∗ 4 + 8 =