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