gcc 4.3.2 https://ideone.com/kptAWE
gcc 5.1 c++14 https://ideone.com/odZKN6
Integer overflow to UB: może zdarzyć się wszystko. Podlinkowane wyniki zawierają się we wszystko
.
Chociaż przyznam, że jestem ciekawy czemu tak się dzieje.
http://goo.gl/rHjIE8 tutaj nie udaje się powtórzyć przy takich samych/zbliżonych flagach kompilacji i wersji kompilatora.
http://melpon.org/wandbox/permlink/5C4m0QJs0YFph8Wt tutaj też nie udaje się powtórzyć.
http://melpon.org/wandbox/permlink/aS5BAG5jwjXpKR7g tutaj faktycznie można to powtórzyć.
Bardzo chętnie przeczytam racjonalne wytłumaczenie dlaczego się tak stało (a nie dlaczego standard mówi, że wszystko może się zdarzyć).
Jeżeli wewnątrz pętli jest std::endl
to wtedy program sie wysypuje. Np. dla samego std::flush
czy '\n'
jest ok. W wersji z std::endl
jedyna możliwość wyjścia z pętli to linia 18: je .L11
, ale wydaje się, że to dzieje się tylko na okoliczność wyjątku (std::bad_cast
, ale co to tam robi tego nie wiem, to wyjątek przy złym dynamic_cast
). Ponieważ to się nie dzieje, program nigdy się nie kończy. http://goo.gl/WB2PGK
Wyrzucenie wypisywania poza main
(do sink
) powoduje, że znów działa. Chyba, że pozwoli się na inlinowanie - wtedy znów się psuje.
Edit: Jest o tym wątek na SO: http://stackoverflow.com/questions/24296571/why-does-this-loop-produce-warning-iteration-3u-invokes-undefined-behavior-an Również zauważyli, że std::endl
ma znaczenie (ale dalej nie wiadomo w jaki sposób dokładnie) i podają podobną analizę co @msm niżej (na różne sposoby).
for (int i = 0; i < 4; i++) {
std::cout << i * 1000000000 << " " << i << std::endl;
}
Następuje analiza w rodzaju:
- wiemy
i * 1000000000
jest w przedziale <-2147483648; 2147483647> (bo jeśli nie jest to mamy UB, więc ignorujemy taką możliwość) - z tego wynika że wartość i w tym wyrażeniu jest w przedziale <-2; 2>
- z tego wynika że wartość i w ciele pętli jest w przedziale <-2; 2>
- ta wiedza jest propagowana dalej. Patrzymy na warunek
i < 4
w pętli - "wiemy" że w tym momencie i jest w przedziale <-1; 3> (<-2; 2>++). - więc maksymalna "możliwa" wartość i w warunku to 3, a 3 < 4.
- z tego powodu warunek redukuje się do
true
- ...i pętla for traci warunek końca (zostajemy z
for (int i = 0; true; i++) { ... }
)
Bardzo podobną analizę wykonują wszystkie nowoczesne kompilatory (chociaz oczywiście z różnym poziomem domyślności), patrz np. trochę podobne http://blogs.msdn.com/b/oldnewthing/archive/2014/06/27/10537746.aspx