Jak to (nie)działa?

4

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ć).

1

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).

8
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

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