Programowanie
Zajmiemy się teraz elementem, który jest główną zaletą aktualnie tworzonego pro-graniu. Mowa o automatycznym umieszczaniu w pamięci wyświetlacza odpowiednich
znaków specjalnych. Z poziomu pliku kd.c będziemy korzystać teraz ze zmiennej localjcdspec. Ab> mieć do niej dostęp, koniecznie dopisz na początku pliku Icd.c, zaraz za dołączen.em Icd.h, dołączenie pliku local.h.
Listing 84 Wyszukiwanie maków specjalnych.
// Dołączyć „local.h*' II!
statlc uint8_t :cd_isSpec(char c)
return (c >- Ux80) Ud (c <■ 0x9f);
static inline uint8_t lcd_Spec2Index(char c)
return c-0x80;
Static uin.,8 t Lcd GetSpec(uint8 t s Lndex)
jint8_t &;
for(a»0; a<ELEMS(lcd_spec); a++)
// Oxff oznacza, że nie ma już wpisów 1f(lcd_spec[a] =■ Oxff) break;
// Jeśli znaleziono... else if(lcd_spec[a] = s_mdex) return aj
// Nic nie znaleziono return pgm_read_byte(
&(local icdspec[s index].ca:t));
// Makro pomocnicze
#deifine LCD SPECNF(spec) (spec > 7)
Listing 85 - Funkcja wyboru znaków specjalnych.
uintE t lcd PrepareSpec(\/oid)
{ "
char* pbuffer ■ lcd_buff©rj uint6_t nj uint£_t cr.t-O; char znak;
// Na początku „zerowanie“ tablicy znaków memset(lcd spec, Oxff, sizeof(lcd_spec));
// dodawanie wpisów
for(n-0; ri<LLfcKi>(lcd_t»u:fer); n-H-)
znak - *pbuffer-H-;
// Jeśli znaleziony znak jest specjalny if(lcdlsSpec(znćk))
{
// Przeszukanie tablicy znak *= lcd Spec2lndex(znak);
// Jeśli nTe znaleziono - dodawanie if(LCD_SPECNF(lcd_GetSpec(znćk)))
{
// dodaj do tablicy tylko jeśli // nie wystąpiło przepełnienie if(cnt < ELEMS(lcd_spec)) lcd_epec[cnt] = znak;
// Licznik zwiększany zawsze // dla statystyki ++cnt;
ł
ł
return ent;
Zobacz listing 84. Przedstawiona tutaj funkcja icd_GetSpec przeszukuje tablicę znaków specjalnych w poszukiwaniu znaku o kodzie podanym jako argument. Jeśli go nie znajdzie -zwraca kod znaku alternatywnego. Jeśli go znajdzie - zwraca indeks w tablicy, pod którym dany znak występuje Pierwsze napotkanie wartości Oxff traktowane jest jako koniec danych -poszukiwanie zostaje przerwane za pomocą instrukcji break. O tym przydatnym słowie możesz dowiedzieć się więcej z ramki Sterowanie przebiegiem pętli.
Funkcja szukająca została napisana w taki sposób, źe zwrócona przez nią dane nadaje się do bezpośredniego wyświetlenia. Ponadto, jeśli znak specjalny znajduje się w tablicy, zwrócony kod będzie zawsze mniejszy niż 8. Kody znaków alternatywnych musza mieć wartości większe, ponieważ inaczej będą pokrywać się z obszarem
ABC... C
Zmienne globalne, deklaracja typu extern, definicja typu static a zasięg nazw
Pewna sprawa, która do tej pory /ustala przemilczana: gdy tworzymy zmienną globalną czy też funkcję glo-halną (nie umieszczamy przed nimi słowa static). to zmienna 'funkcja) ta jest widoczna w całym progra-m.e, nie tylko w pliku, w którym /ostała /definiowana. Załączone obrazki wyjaśniają sprawę na zmiennych, jednak dokładnie te same własności mają funkcje.
Na rysunku A pokazuję, co się stanie, gdy spróbujemy w dwćch różnych plikach użyć zmiennej globalnej o takiej samej nazwie - jest to kolejny pnwód, aby nazwy zmiennych globalnych czy funkcji poprzedzać nazwą pliku (tak jal In robimy).
Jeśli zmienna jest globalna dla całego programu, wydaje się, że możliwy powinien być dostęp tak, jak to pokazuje rysunek B - jednak zapominamy w tym przypadku, że kompilator działa na każdym pliku oddzielnie i nic posiada informacji linkera. Prawidłowy dostęp do zmiennej i innego pliku pokazuje rysunek C. W tym przypadku istnieje pewne różnica pomiędzy zmiennymi a funkcjami - przy deklarowaniu funkcji zewnętrznej można pominąć słowo eiteru - deklaracja funkcji domyślnie jest
zewnętrzna - porównaj tę informację z tyir., co robimy w plikach nagłów kowych.
Rysunek D pokazuje, co się dzieje, gdy tworzymy zmienną statyczną. Część tekstu zaznaczyłem tutaj gwiazdką - niech nie wprowadzi Cię w błąd określenie. że kompilator rozmieszcza zmienne - nie jest on w stanie wybrać ostatecznego miejsca w pamięci procesora, gdzie zmienne czy funkcje zostaną umieszczone - informacje potrzebne do takiego działania posiada jedynie linker.
W pliku obiektowym nie jest to bezpośredni adres, lecz adres rei oko walny - linker
zadecyduje ostatecznie, pod jakim przesunięciem umieścić cały kod. Jednak taktem jest, że do linkera informacja o zmiennej statycznej nie dotrze. Co ciekawe i przydatne jeśli zmiennej lub funkcji statycznej ani razu nie wywołamy - kompilator nic umieści jej kodu w pliku wynikowym.
Przykłady• listing 83 i 93.
o
int |
<nt ll»IUMli | |
int a_MU*in»U |
Tutaj znajduje się mwnacja /p o zmiennej:
Kompiator nie •ozm lesz cza zmennycn jjlobolnyoh w pamięci. Umieszcza jodynie informację o nicłi. Odwołania do zmiennych w pliki retofcowelny-n są
Lnktor próbuje rozrrleteić zmienne gobalno w pamięci craz zamienia symboliczne odwołania na prawidłowo instrukcje kodu
Tutą z widuje aif hformacja o zml&nknych: o_ zmienna 1 a zmienna 1
Błąd! Zmierna a_zmł9nr* f jest deklsrowana dwa raz/! Linker nie wie z którą zmienną potą:zyć odpcwieone
“otfwutenia. Gdyby obio deklaracje tworzyły zmonoe różnego typu linrernie wodziałby nawet. ile pamięci ma zająć.
W porządku costaje jedyni#
Informacjo Łezrrionna^a litnłaje oraz jakiego jest typu Na tej podBUnv«
jont w U ario utworzyć
symboliczne odwołania
Tttai znajduje sio Informacja o zmiennych b_zmiarma_1 oraz wykonywany jest symboliczny doetęp do zmiennych a jnwnra_ 1
i b zmienna 2
pamięci, oraz zamienia symbołlczne odwołania na instrukcje kodu maszynowego.
O
Błąd! Kompilator nie ma pojęoa co to ,-est zn\ierna_a
® Iran
p | |
pHk_m.c |
..io, u Int mictim o; |
ktatłe Int |
Int wiUruu b; |
(...) | |
uleuta.b • inUini i] |
Kompilator otrzymuj# Informacje, źe zmiems_a iitneje i jest typu Inl Twcrzone są symboiczne odwołani* do toj nioAnlo
T Jtaj znajduje się Informacja o zmlonnych: b_zmiorno_1 oraz wytonywanyjes symboliczny dostęp cło zmiennych a_nmnna_i Ił) zmtenna_2
patrz tekst
Brak tjtą informaci o zmiennej ejuntennai. Kompilator nia tworzy odwołah symbolicznych do a. zmienno f - zmienna 8 ta tyczna może być już na etapie kompilacji umioazc2ono w pomięci*.
t W pliku f.likji.o występuje odwołańc cło a zmienna J, Nie ma takiej zniennej!
Elektronika dla Wszystkich Maj2006 47