přetečení int v C arduino

Petr Zapadlo zapik na email.cz
Pátek Červenec 18 17:29:31 CEST 2014


Děkuji za detailní vysvětlení.
Zatím jsem psal jen  v asembleru a tam jsem si "datové typy" hlídal 
striktně ručně.
Tady se mi zalíbila volnost rozletu a "automatika" a už jsem na to dojel :-)

Petr


Dne 18.7.2014 16:22, Jan Waclawek napsal(a):
>> Dne 18.7.2014 10:55, Jan Waclawek napsal(a):
>>> V skutocnosti nepotrebujete drzat tie premenne den, hodina, minuta atd. ako
>>> long, pokojne mohli ostat ako int, len v tych operaciach nasobenia, kde to
>>> pretecenie nastava, ich treba explicitne pred pouzitim pretypovat na long.
>>>
>> Jak to pak probìhne technicky, ten pùvodní int se  tou operací
>> pøetypování  "odkopíruje" do longu a následnì zase zkrátí na int?
>
> Ano, da sa to tak chapat.
>
> Vas povodny zapis je takehoto typu:
>
> int16_t a;
> uint32_t b;
>
> b = b - a * 12345;
>
> Toto sa vykonava nasledovne:
>
> 1. a * 12345
>
> Pred vykonanim nasobenia sa urobia "usual arithmetic conversions", t.j. sa
> oba operandy prevedu na "najmensi spolocny typ" (este predtym, ak je
> niektory operand "kratsi" ako int, tak sa prevedie na int alebo unsigned
> int, to sa vola integer promotions, ale to tu nenastava tak sa tym
> momentalne netreba zapodievat). Ta konstanta 12345 ma v avr-gcc implicitny
> typ int16_t (ak by bola vacsia ako 32767, tak bude mat implicitny typ
> int32_t). Premenna a ma explicitny typ int16_t, takze "najmensi spolocny
> typ" je prave int16_t. Vykona sa nasobenie, ktoreho vysledok ma implicitne
> tiez then "najmensi spolocny typ" ako jednotlive operandy (C99 6.3.1.8),
> takze tam je prave to riziko pretecenia. Norma riesi taketo pretecenie
> (C99 6.5#5) ako nedefinovane spravanie, takze nasledkom moze byt uplne
> cokolvek, od spravneho vysledku (dosiahnuteho nespravnym postupom), cez
> nespravny vysledok az po predcasne ukoncenie prekladu alebo vykonavania
> prelozeneho programu. Je na zodpovednosti autora programu, aby taketo
> pretecenie nenastalo. Castokrat (aj u AVR) sa typicky taketo nasobenie
> jednoducho vykonava bez kontrol a pri preteceni sa zahodia vyssie bity.
>
> 2. Vysledok z predchadzajuceho kroku (s implicitnym typom int16_t) je
> odcitany od premennej b s typom uint32_t. Znova sa najprv vykonaju "usual
> arithmetic conversions", najmensi spolocny typ je uint32_t a na ten sa
> medzivysledok predchadzajuceho kroku prevedie jednoducho pridanim nulovych
> vyssich bitov (nijako sa pri tomto neberie do uvahy napriklad to, ze by
> ten medzivysledok mohol byt zaporny, takze napr. kebyze je -12345, co je
> 0xCFC7, tak po konverzii na uint32_t je to stale 0x0000CFC7, ale toto uz
> znamena 53191 - uz chapete preco varujem pred miesanim neznamienkovych a
> znamienkovych typov?). Potom sa tie dve uint32_t hodnoty odcitaju.
> Podobne, ako pri nasobeni, aj tu moze nastat pretecenie, znova je
> nasledkom nedefinovane spravanie, znova je zodpovednost autora, aby to
> nenastalo.
>
> 3. Vysledok predchadzajuceho kroku (s implicitnym typom uint32_t) ma byt
> priradeny do premennej typu uint32_t. V tom problem nemoze byt.
>
> ---
>
> Vas problem je v kroku 1, lebo vzhladom na predchadzajuci postup v tej
> funkcii, nikde inde to pretecenie nastat nemoze. Tento problem vyriesite
> tak, ze prinutite kompilator, aby ten "najmensi spolocny typ" bol
> dostatocne velky na to, aby pretecenie nenastalo (a uint32_t bude pre Vas
> ucel urcite stacit). Preto je riesenim bud
>
> b = b - (uint32_t)a * 12345;
>
> alebo
>
> b = b - a * (uint32_t)12345;
>
> alebo
>
> b = b - a * 12345UL;
>
>
> Premenna a bude v pamati aj nadalej len 16-bitova (aj ked zas a znova,
> doporucujem uint16_t) - ak vobec bude v pamati, je to len lokalna
> premenna, na druhej strane ich tam mate dost vela a ak su 32-bitove, tak
> sa do registrov asi nezmestia a naozaj aspon niektore budu v pamati.
> Naviac ostatne operacie na tej premennej sa tiez mozu robit len 16-bitovo,
> takze ta optimalizacia sa s najvacsou pravdepodobnostou oplati.
>
> ----
>
> Za tu spravnost vypoctu zaplatite aj dan: u AVR sa pouzije nasobenie 32-bit
> * 32_bit = 64-bit, co je pomerne zdlhava zalezitost a riesi sa volanim
> kniznicnej funkcie (ktora samozrejme musi byt pritomna => spotrebovana
> FLASH).
>
> Ale ponukam Vam fintu (ktora vsak funguje az od avr-gcc v4.5
> (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=23726 ) - neviem, co
> aktualne mate v tom Arduine, naposledy co som sa pozeral tam bola nejaka
> dost predpotopna verzia): namiesto
>    a = b / 12345;
>    b = b - a * 12345UL;
>
> to zapiste ako
>
>    a = b / 12345;
>    b = b % 12345;
>
>
> div aj mod sa vypocita v jednom volani funkcie pre delenie, a netreba uz
> nasobit.
>
> wek
>
>   
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.cz
> Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list



Další informace o konferenci Hw-list