přetečení int v C arduino
Jan Waclawek
konfera na efton.sk
Pátek Červenec 18 09:44:22 CEST 2014
Klucove slovo je "usual arithmetic conversions" (C99 6.3.1.8 a cely 6.3 kvoli konverziam). Plus implementacne definovane typy, tu (Arduino = avr-g++) je int == int16_t a unsigned long == uint32_t.
Zjednodusene povedane, kazdy binarny operator "prinuti" svoje operandy aby si "zjednotili" typ na najblizsi vyssi, ktory obom vyhovuje.
Pri den*86400 je este jeden faktor, a to implicitny typ konstanty (C99 6.4.4.1). Desiatkova konstanta, ktora "nevojde" do int, je long int, co je tu int32_t, takze na int32_t sa prevedie aj den a vysledok nasobenia je tiez int32_t. Nasledne je pri odcitavani prevedeny tento vysledok na uint32_t (ale kedze je to 0, nezmeni sa), pretoze druhy operand odcitania cas 1 je typu uint32_t.
Problem zrejme nastane az pri hodina * 3600, pretoze 3600 je implicitne int t.j. int16_t, takze sa nasobi int s int, a tam to pretecenie nastane.
Preco po odcitani je vysledok 65536, je mi zahadou. Norma samozrejme pri preteceni dovoli urobit hocico, ale od avr-g++ by som ocakaval, ze vysledok nasobenia (36000=0x8CA0) ktory sa tu zmesti do 16 bitov, akurat pretecie do znamienka) rozsiri znamienkovo na 32 bitov, skonvertuje na uint32_t (t.j. 0xFFFF8CA0), urobi odcitanie (vysledok je 0x00010000) a spat explicitnu konverziu na int16_t, takze podla mna by to v tomto konkretnom pripade malo dopadnut "korektne" (spravny vysledok dosiahnuty nespravnym sposobom). Nechapem, preco to tak nie je.
Mimochodom, zapis int(vyraz) je korektny len v C++.
wek
On Fri, 18 Jul 2014 09:03:07 +0200
Petr Zapadlo <zapik at email.cz> wrote:
> Zdravím,
>
> cas1 je ulong - tj na arudinu očekávám 32bit.
> Tam je rezerva dost velká.
> Záleží jak se přesně počítá,
> cas1 je ulong, den je int. Tedy člen den*86400 bude do intu velký, ale
> do ulong vyhovující.
>
> Jak dochází k přetypování?
>
> Petr
>
>
> Dne 18.7.2014 08:28, Pavel Kutina napsal(a):
> >
> > Skoly nemam, ale at na to koukam, jak chci, tak mi vychazi, ze v radku
> > cas1=cas1-den*86400;
> > bude "den" vzdycky mimo rozsah int i uint (tedy za predpokladu, ze den
> > je vetsi nez jedna, coz tak nejak obvykle byva). Pritlacil bych na long.
> >
> > Pavel Kutina
> >
> >
> > Dne 18.7.2014 8:02, Petr Zapadlo napsal(a):
> >> Bude,
> >> to jsem pochopil, proto jsem taky změnil délku datového typu.
> >> tady mě ram netrápí, ale chci chápat co se děje do budoucna.
> >>
> >> Zakopaný pes je zřejmně zde:
> >>
> >> cas1=cas1-den*86400; //cas1=36000
> >> hodina=int(cas1/3600); //hodina=10, cas1=65535
> >> cas1=cas1-hodina*3600;
> >>
> >> v které přesně operaci to přeteče a proč?
> >> cas1 unsigned log, takže rezerva je tam dost velká.
> >> Zápis:
> >> int(cas1/3600)
> >>
> >> chápu tak, že výpočet se provede v ulong a převede se na int.
> >>
> >> Je to tak?
> >>
> >> Díky
> >>
> >> Petr
> >>
> >>
> >
Další informace o konferenci Hw-list