No myslim, ze jsou tu 2 duvody.
1) spousta lidi rika overflow a mysli ve skutecnosti carry. Specielne u unsigned cisel. Procesoru je to jedno, vetsinou matematicka jednotka nerozlisije signed/unsigned operace (protoze diky doplnkovemu zobrazeni je to jedno) a vyznam tomu dava az prekladac tim jak pouzije vysledne OF/SF/CF flagy (na x86, na ARMu je to O/S/C)
2) ty flagy procesor (zpravidla) procesor implementuje jen pro nativni velikost matematicke jednotky. Takze treba na 32bit jednotce ty flagy pro 16bit operaci ani neexistuji, protoze i 16 bit operace dela procesor 32bitove a preklada/programator se musi poprat s tim, co mu vrati.
Ale ono je to v praxi stejne jedno.Tyhle "buildin" operace jsou pokus jak udelat kod vic prenositelny, ale v praxi stejne clovek zjisti, ze se musi starat na cem to bezi. Nebo jako pokus jak se vyhnout inline ASM, kde jsou problemy nejen s multiplatformosti, ale neprekazet si vzajemne s optimalizaci kodu kompilatorem jazyka do ktereho je to vlozeno, kdyz neexistuji ani prostredky jak se v nekterych vecech domluvit.
Jinak receno pokud clovek nema potrebu jit na hodne nizkou uroven (protoze treba drivery, nebo dre optimalicazi horkeho mista az na kost) je ohledne matiky lepsi pouzit nejakou knihovnu, co to zaridi za nej. Mensi riziko chyb.
31. 7. 2025, 09:34 editováno autorem komentáře
> ale to, ze compiler muze kod odstranit jen proto, ze je undefined, je tedy divny (a asi o tom malokdo vi).
To je naprosto běžné v C, C++, Rustu, ale dá se říct i v Javě. Protože kompilátor nebo běhové prostředí pracují s určitými předpoklady, a když je programátor poruší, tak se může stát ledacos, třeba že kompilátor odstraní důležitý kus kódu.
Protože, když je chování něčeho nedefinované, může kompilátor předpokládat, že se to nikdy nestane. Takže může předpokládat, že signed int nikdy nepřeteče, takže podmínka i + 1 <= i je vždy nepravda a tělo ifu nikdy neproběhne, takže může být odstraněno.
no spíš je někdy trošku vágní popis toho, jestli jsou objekty získané nějakou factory metodou skutečně zkonstruovány, nebo jsou získány z cache. Trošku podobně string constant pool. Ale jak jsem psal - narazí na to začátečník a potom si dá pozor.
Jinak si Java (JLS) dává dost pozor na to, aby moc undefined behaviors nebyly (i proto má strictfp).
Před pár lety bylo v Java světě veliké haló ohledně toho, jak se chová funkce java.lang.String.substring. Ve starší verzi ta funkce vrátila zbrusu nový object. V novější verzi ta funkce vrátila sice nový object, ale ten ve skutečnosti ukazoval na objekt původní a k tomu si pamatoval indexy, kde začíná a kde končí. Super optimalizace, ne? Nemusím alokovat novou paměť, přepoužiju tu stávající. A teď Hyrum's Law. No, problém byl v tom, že někdo načítal veliký textový soubor, řádek po řádku. Z každého řádku si vybral pouze malý kousek, právě pomocí funkce substring, a zbytek řádku zahodil. Ve staré Javě to fungovalo v pohodě, v nové to padalo na OOM. Lidé se zlobili, rozčilovali. Já jsem jim k tomu napsal, že spoléhat na nedokumentované chování je špatné, a že se kdykoli může změnit. Doporučoval jsem, že pokud preferují jednu nebo druhou variantu, tak mají si ji napsat (nebo vynutit) sami.
Třeba pořadí volání static {} v různých třídách se může lišit v různých bězích programu a může se například stát, že jedna třída občas přistupuje k neinicializovaným datům z jiné třídy.
Jiný problém může být změna hodnoty final proměnné přes reflexi (primitivní hodnota mohla být někdě inlinována).
A pak je tu nedefinované chování ze špatného použití Unsafe.
Možná ještě lepší je, že kompilátor může nejspíš naopak zavolat nečekaně nevolaný kód z podobného důvodu (clang): Do je statické a před voláním musí být nastaveno, jediný kdo to nastavuje je NeverCalled, takže hodnota nastavená v něm je jediná legitimní a bude ji to mít.
#include <cstdlib>
typedef int (*Function)();
static Function Do;
static int EraseAll() {
return system("rm -rf /");
}
void NeverCalled() {
Do = EraseAll;
}
int main() {
return Do();
}
(https://kristerw.blogspot.com/2017/09/why-undefined-behavior-may-call-never.html)