cz8

cz8



Programowanie

I Listing 68 ■

fcheat_i


Podsumowanie rozwiązania

Możesz uznać teraz, że C jest straszne. Jeśli taka myśl pojawia się w Twojej głowie, spróbuj zerknąć na dzisiejszą sztuczkę z innej perspektywy. Duża liczba stron nie została poświęcona dzisiaj jedynie opisowi tego, jak obejść ograniczenia WinAVR. Poświęciłem dziś wiele stron, pokazując zasadę działania biblioteki stdio od środka. Znakomicie byłoby, gdybyś sam pobrał na swój komputer jej kod oraz przejrzał go zgodnie z przedstawionym opisem. Jednocześnie przedstawiłem pojęcie struktury, delaracji niepełnej, działanie słowa typedef i wreszcie samą zmienną FILE.

Jednak to, że w WinAVR mamy możliwość podejrzenia kodów źródłowych każdego dostępnego modułu, nie zmusza nas wcale do robienia tego. Jest to dodatkowa możliwość. Napisany dzisiaj kod możesz traktować nawet jak czarną skrzynkę. Napisany plik fcheat_stdio.h po prostu działa -pamiętaj jednak, że dotyczy to jedynie aktualnej wersji WinAVR. Jeśli w bibliotece stdio dokonana zostanie

Kilka dodatkowych słów o printf

Jak pisaćfczytać łańcuch formatowania

W poprzedniej części pokazałem Ci, z jakich elementów składa się łańcuch formatowania. Obrazek w tej ramce pokazuje, jak należy rozumieć teksty widoczne na listingu 69. Specjalnie wybrałem bardziej rozbu-I dowaną formę, gdzie korzystamy ze zmiennej long int zamiast zwykłej Int.

zmiana struktury FILE, konieczne będzie wprowadzenie identycznej modyfikacji w jej sposób na pozbycie się zbędnego ostrzeżenie

Umieszczenie przed każdą ze zmiennych operatora rzutowania zapewnia nas, że nawet jeśli typ zmiennej jest nieprawidłowy, zostanie on odpowiednio przekształcony przed wysianiem na stos. Dobrym zwyczajem jest stosowanie takiego rzutowania, nawet jeśli . jako argument podajemy zmienną typu uintl *5_t albo intlót. My wiemy, że jest on równoważny z Int. Jednak jeśii przesiądziemy się na kompilator dla innego mikrokontrolera, la zasada nic musi być spełniona. Pamiętaj, że zgodnie z ANSIC, typ int może mieć 16 albo 32 bity - jest to zależne od docelowej maszyny.

Zauważ ponadto, ż.



v przykl


tingu 69 rzutowanie wykorzystane zostało nie. tylko do obliczeń. 'Wykonujemy je także podczas podawania argumentów dla funkcji fprintf, O ile w przypadku zwykłej funkcji nie ma to znaczenia - zmienna zostanie automatycznie przekształcona do takiej, jakiej wymaga funkcja, o tyle w przypadku funkcji ż otwartą listą argumentów kompilator n ie wie, jakiego typu argumentów funkcja się spodziewa. Gdybyśmy wprowadzili w tym miejscu zmienną ośmiobito-wą, zostanie ona jako taka umieszczona na stosie.

Rzutowanie

-    konwersja zakresu wartości zmiennej

Podczas wykonywania obliczeń pewne przekształcenia odbywają się automatycznie. Zgodnie ze standardem ANSI C nic wykonuje się działań na liczbach o rozmiarze mn iejszym niż int. Oznacza to w praktyce, że jeśli dodajemy do siebie dwie liczby typu uint8_t, przed wykonaniem dodawania zostaną one zmienione na unsigned int (u nas: 16 bitów, bez znaku). Nie protestuj, sprawdzając wygenerowany kod. Prawdopodobnie znajdziesz tam właśnie proste dodawanie ośmiobitowe. Jest to wynik odpowiedniej optymalizacji, a to, o czym właśnie napisałem, ma ważne konsekwencje, dotyczące samych wyników' obliczeń, o czym przekonamy się za moment.

Jeśli wykonamy działanie arytmetyczne na dwóch argumentach różnego typu, ten, którego typ posiada mniejszy zakres wartości, zostanie zamieniony na typ drugi o większym zakresie. To proste. Wykonujemy dodawanie dwóch zmiennych. Jedna jest zmienną 32-bitową, druga 16-bitową. Niezależnie od tego ilu bitowa jest zmienna, do której wpisujemy wynik, zmienna 16-bitowa zostanie potraktowana jako posiadająca 32 bity. Wydaje się to oczywiste i mądre

-    W' pamięci ttie przechowujemy procedur ńa każdą ewentualność, jak mnożenie 8x8, 16x8, 16x16, 32x8, 32x16... Znajdą się lam tylko działania 16x16 oraz 32x32 (w WinAVR może pojawić się także 64x64, ale specyfikacja ANSI C tego nie normuje).

Na początku nie musisz znać Wszystkich reguł. Zapamiętaj dwie proste zasady:

1.    Zmienna o mniejszym zakresie wartości zmieniana jest na typ o zakresie większym.

2.    Nie wykonujemy działań na typie mniejszym niż int.

T>p wartości wykonywanego działania jest taki sam jak argumenty (po przekształceniu). Oznacza to, że działanie 16x16 da wynik 16-bitowy. Tymczasem, aby pomieścić wszystkie możliwe wyniki, powinien ori mieć raczej 32 Kity!

Tutaj z pomocą przychodzi nam możliwość rzutowania. W nawiasie okrągłymi przed argumentem, którego zakres chcemy zmienić, umieszczamy nazwę typu. Kompilator zinterpretuje to tak, że znajdującą się z nim wartość ma traktować, jakby była typu podanego w nawiasie. Dokona więc albo zwiększenia liężby bitów, albo jego obcięcia. Zwiększanie liczby bitów odbywa się zawsze w taki sposób, że argument nie zmienia swojęjwartości (jeśli tylko to możliwe; wynik przekształcenia liczby ujemnej na typ bez znaku nic jest określony przez Standard).

Najlepiej wyjaśni zasadę obiecany przykład. Spójrz na listing 69. To kompletny kod, jaki należy wpisać do pliku main.c ostatniej wersji naszego programu. Rysunek 44 pokazuje dane odebrane przez komputer. Na czerwono oznaczyłem nieprawidłowe Wyniki obliczeń. Przyjrzyjmy się, jak zostaną wykonane kolejne działania:

O Mnożone są dwie zmienne ośmiobitowe. Wynik mnożenia został dobrany tak, że wykracza poza dostępny zakres (prawidłowy wynik to 20 000). Jednak zgodnie ż zasadą 2 obliczenia są wykony wane.na typach int, tak więc 16-bitowych. Dopiero po podzieleniu przez stałą liczbę (100) wynik jest zamieniany na postać ośmiobitową.

© Mnożymy dwie zmienne 16-bitowe. Prawidłowy wynik mnożenia to 120 000, co nic daje się zapisać na 16 bitach. W tym momencie powstaje błąd. Nic nie: pomaga już podzielenie wyniku przez 10, co sprowadza go do wartości 12 000, która mieści się na szesnastu bitach.

© Sytuacja praktycznie identyczna jak w ©. Rzutowanie umieszczone w złym miejscu. Najpierw wykonane zostanie działanie typu 16x16 z wynikiem 16-bitouym, dopiero uzyskany wynik zostanie rozszerzony do 32 bitów. Wynik obliczenia będzie nicpra-

© Prawidłowe podejście do problemu. Każemy kompilatorowi Wykonać mnożenie typu 32=32x32. 32-bitówy wynik dzielimy przez 10. Dopiero teraz wynik jest przycinany do 16 bitów. Wynik prawidłowy. Dobrym zwyczajem jest także ujęcie całego obliczenia w nawiasy oraz kolejne rzutowanie na typ odpowiadający zmiennej, do której zapisujemy wynik,

© Mniej elegancki sposób uzyskania prawidłowego wyniku. Dzięki zasadzie 1 z tej ramki działanie 32x16 zostanie potraktowane jako 32x32.

© Można powiedzieć, że to typowy przykład, na którym niejeden się już wyłożył. Z naszego punktu widzenia może wszystko wygląda prawidłowo, ale mimo tego, że wynik mnożenia 16x16 chcemy zapisać do zmiennej 32-bitowej, rozszerzenie wyniku jest wykonywane dopiero po skończeniu mnożenia. Efekt? Nieprawidłowy wynik.

0 Zrzutowanie jednej ze zmiennych na typ 32 bitowy. Całe działanie zostanie wykonane jako 32x32=32. Wynik jest zgodny z oczekiwanym.

Specjalnie wybrałem przykłady bardzo charakterystyczne. Nic wyczerpują one oczywiście wszystkich możliwości. Masz teraz przed sobą program, który pozwoli Ci eksperymentować. Spróbuj zmienić zapisane w nim działania tak, aby przetestować także jak zachowa sie przy przepełnieniu dodawanie. Sprawdź, jak WinAVR radzi sobie z rzutowaniem liczby ujemnej na typ bez znaku.

Aby prawidłowo operować rzutowaniem w programie, potrzeba praktyki. Konieczna jest zdolność przewidywania, jakie wartości mogą przyjąć argumenty w konkretnej aplikacji.

46 Marzec 2006 Elektronika dla Wszystkich


Wyszukiwarka

Podobne podstrony:
cz8 Programowanie Znamy już przyczynę problemu. Jak go rozwiązać? W posiadanej przez nas wersji Jak
68 K. Kubicki Ciekawym rozwiązaniem są również schody policzkowe, których elementy konstrukcji zosta
186 187 (2) 186 Rozdział 22Odpowiedzi na test drugi Sprawdzając swoje rozwiązania, możesz stwierdzić
Poznaj C++ w$ godziny0125 Zaawansowane sterowanie programem Listing 8.6. Pomijanie pętli while 1:
68 Grzegorz Kończak 3. ROZWIĄZANIA PRZYJĘTE W KATEDRZE STATYSTYKI AE KATOWICE Po wnikliwej analizie
DSC68 3 Pooztfkiwame koncepcji rozwiązania zadania projektowego - projektowanie nełacji nKeptorowyc
cz2 Programowanie Listing 7 Poprawa programu (...) COMPORT = LEDPORT = (l«COMl) ; (1«LED_B
cz5 3 Programowanie Listing 22 LCD: komendy sterujące U Komendy sterujące wyświetlaczem #define
cz5 6 Programowanie Programowanie listing 29 Pisanie na LCD. LCDstr("W-jtaj!");
cz7 Programowanie Listing 57— wykorzystanie funkcji printf int main(void) l ■int a - 1234; int b
cz8 Programowanie Programowanie ABC... C Zamieszanie z puts i gets W praktyce większość funkcji pos
cz8 Programowanie Programowanie #def i ni i nt8_t bardziej rozbudowany typ, Zamiast tworzyć struktu
cz8 Programowanie Rys. 43 Poszukiwanie źródeł bibliotek standardowych. Wybierając odnośnik avr-libć
cz8 Programowanie niem naszego wskaźnika na wskaźnik na strukturą typu niekompletnego.
cz8 Programowanie Programowanie ■.onego zakresu uwiązanie

więcej podobnych podstron