bug w gcc??

Mar 22, 2006 9 Replies

Witam walcze z gcc pod AVR (avr-gcc (GCC) 3.4.5), i chyba znalazlem buga gdy mnoze liczbe zzakresu 0-9 (U8) przez stala 10 000, mnozenie dziala poprawnie do rezultatu nie wiekszego niz 30 000. Zmienna jest typu U32, przy unsigned integer, long jest tak samo. Dzialo by sie tak, gdybym zadeklarowal ja jako U16, ale mam U32 wynik mnozenia dla wartosci wiekszych niz 3 jest : FFFFxxxx Co ciekawe mnozenie * 100 000 dziala OK.



oto linsting przy ktorym sa takie jaja: przetwarza on ciag liczb BCD pobranych z klawiatury (input_buffer) na 32bit (input_frequency )



U32 input_frequency ; input_frequency = 0; input_frequency = input_buffer[6] + input_buffer[5] *10 + input_buffer[4]*100 + input_buffer[3]*1000 + input_buffer[2]*10000



+input_buffer[1]*100000;

no i on nie dziala poprawnie natomiast jak obejde problem mnozenia przez 10 000 tak:



U32 input_frequency ; input_frequency = 0; for (U8 nr=1; nr< (input_buffer[2]+1); nr++) { input_frequency+=10000; } input_frequency += input_buffer[6] + input_buffer[5] *10 + input_buffer[4]*100 + input_buffer[3]*1000 + input_buffer[1]*100000;


to wszystko jest w porzadku



czy ja czegos nie rozumiem czy to bug?


U¿ytkownik "Greg" snipped-for-privacy@CERN.CH napisa³ w wiadomo¶ci news:dvru08$r73$ snipped-for-privacy@sunnews.cern.ch...

W mno¿eniu (tym przez 10000) ¿aden czynnik nie jest U32 wiêc o co chodzi ? P.G.

o to chodzi, ze jak pomnoze 3*10 000 to mam 30 000 (0x00007530) ale jak pomnoze 5* 10 000, to mam jakies krzaki, np 0xFFFFF350 zamiast

0x0000C350 wraz ze swoimi konsekwencjami jak wyswietlam to na LCD natomiast jak pomnoze 5 przez 100 000 to mam prawidlowo: 0x0007A120 dlatego musialem uzyc innego algorytmu z dodawaniem

co jest grane?

Greg napisał(a):

3, 5 i 10000 to dla avr-gcc stałe 16-bitowe i ich mnożenie daje wynik 16-bitowy. 100000 to stała 32-bitowa, więc wynik mnożenia z jej udziałem jest 32-bitowy. żeby stała mniejsza od 65536 była traktowana jak 32-bitowa trzeba dodać na końcu ,,L'' dla stałej ze znakiem lub ,,UL'' dla stałej bez znaku. w Twoim przypadku powinno być mnożenie przez 10000L, nie 10000.

w.

Potwierdzam, ze 2h mi zajęło szukanie błędu w swoim programie jak w jednej ze staluch zapomniałem dodać sobie przyrostka U. A przecież wszystko to jest opisane w standardzie ANSI C jak byk :)

Dzieki wielkie, jutro przetestuje ale nie daje mi spokoju to, ze przeciez zadeklarowalem zmienna 32 bit i dodawalem do niej 16 bit, wiec skad te FFFF sie wziely? dlaczego dodawanie zmiennej n* 1000 nie powodowalo takich problemow? tylko te n*10000

czy tylko przypadkiem dla mneijszych liczb tak mi wyszlo, ze w pamieci byly zera zamiast 2 najstarszych bajow i kompilator potraktowal ja jak ozmienna

32bit?

Tak czy inaczej dzieki!

10000 mieści się jeszcze w typie int ze znakiem. Zauważ, że działa dobrze do 30000, bo następny wynik, 40000 przekracza już dopuszczalny rozmiar dla typu signed int. Dla 100000 jest też ok bo tu już przy mnożeniu nawet przez 9 nie przekracza się zakresu dla zmiennej zarówno signed jak i unsigned long. Jak proponowal przedpiśca przyrostek L a nawet dla pewności UL załatwi sprawę.

Greg(G.Kasprowicz) przemówił ludzkim głosem:

Ano stąd, że zmienna 16-bitowa była ze znakiem, a rzutowanie 16-bit ze znakiem na 32 bez znaku powoduje w gcc ekspansję ze znakiem (czyli najstarszy bit zmiennej 16-bit jest powielany na dwa najstarsze bajty zmiennej 32-bit).

Wklep sobie coś takiego i sprawdź kod wynikowy:

volatile uint32_t a; volatile int16_t b;

b=-15000; a=b;

Z tego co pamiętam to ansi c nie specyfikuje, co powinno się stać ze znakiem przy konwersji signed->unsigned, więc w różnych kompilatorach może być różnie.

Dzieki za wyjasnienie, wszystko juz jasne. Pozdr

jeszcze raz dzieki, wszystko teraz ladnie dziala, wlasnie sprawdzilem:)

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required