C dla kaûdego (cz. 1.) ---------------------- POCZÂTKI Jëzyk C to dzisiaj jeden z najpopularniejszych jëzyków programowania, a bez wâtpienia najpopularniejszy jëzyk programowania wyûszego poziomu na Amidze. Kamil Iskra, Dariusz Ûbik Moûna by wymieniê wiele zalet jëzyka C, ale naszym zdaniem naprawdë waûne sâ tylko trzy. -- Prostota. C jest bardzo surowy, moûna wrëcz powiedzieê -- ascetyczny. Trzon jëzyka jest niezwykle skromny, dziëki czemu îatwo go opanowaê (naszym zdaniem znacznie îatwiej niû np. promowany w polskim szkolnictwie Pascal). C jest elastyczny i nakîada na programistë niewiele ograniczeï. -- Powszechnoôê. Niemal kaûda publikacja na temat programowania Amigi dotyczy wîaônie tego jëzyka. W tym jëzyku jest napisany system operacyjny naszego komputera (niecaîy -- czëôê, tzn. fragmenty wymagajâce maksymalnej prëdkoôci, zostaîa napisana w asemblerze). -- Bardzo dobre kompilatory. Jest ich wiele. Od tych dziaîajâcych juû na A500 z 0,5 MB RAM, aû po kolubryny ledwie pracujâce na A1200 z 6 MB RAM. Kompilatory Co do róûnych kompilatorów, to od razu pojawia sië pewien problem. Po prostu róûne kompilatory sâ ze sobâ nie do koïca zgodne. My, podobnie jak [sts] (ach, wy tajniacy -- patrz Magazyn AMIGA 6/94, artykuî "SAS C") uwaûamy, ûe najlepszy z dostëpnych na Amidze kompilatorów to SAS/C 6, wiëc wszystkie przykîady bëdâ pisane z myôlâ o nim. Nie powinno byê jednak wiëkszych problemów przy uûywaniu innych kompilatorów. Co do opcji kompilatora, to sugerujemy zadbaê, aby typ "char" byî bezznakowy (wartoôci od 0 do 255, a nie od -128 do 127). W SAS/C 6 robi sië to podajâc opcjë UCHAR, w Manx Aztec C 5 opcjë -PP, w GNU CC opcjë -FUNSIGNED-CHAR. Naleûy sië równieû upewniê, ûe typ "int" jest 32-bitowy (long-int), a nie 16-bitowy (short-int) -- kompilatory powinny mieê standardowo ustawionâ wîaôciwâ wartoôê. Program kursu Czas napisaê, czego chcielibyômy Was nauczyê i co zakîadamy, ûe juû umiecie. Zaczynajâc od tego drugiego: NIE bëdziemy uczyê podstaw jëzyka C. Na ten temat istnieje mnóstwo publikacji, poza tym podstawy sâ na kaûdym komputerze takie same, a wiëc moûna sië uczyê nawet z ksiâûek o pececie. My polecamy zdobycie "biblii jëzyka C" -- ksiâûki "Jëzyk ANSI C" autorstwa Briana W. Kernighana i Dennisa M. Ritchie (jest to nowa pozycja, wydana przez WNT, Warszawa 1994 -- nie polecamy pierwszego, przestarzaîego juû, wydania). Ksiâûka ta opisuje w doôê przystëpny sposób standard jëzyka, bez ûadnych pecetowych rozszerzeï (jest tylko jeden rozdziaî o Unixie). Czego wiëc chcemy Was nauczyê? Chcemy daê Wam podstawy niezbëdne do pisania zgodnych ze ôrodowiskiem systemu operacyjnego aplikacji. Moûna by wiëc powiedzieê, ûe kurs ten to nie kurs jëzyka C, ale kurs programowania zgodnego z systemem operacyjnym. Co chcemy przez to powiedzieê? To, ûe zdecydowanâ wiëkszoôê zawartych w tym kursie informacji bëdâ mogli wykorzystywaê nie tylko programujâcy w C, ale równieû programujâcy w asemblerze, Pascalu, E itd. Nasz kurs jëzyka C nie jest pierwszym w polskiej prasie komputerowej. Co wiëc nowego mamy zamiar wnieôê w stosunku do kursów prowadzonych kiedyô przez Bohdana R. Raua w "Amigowcu" i Jarosîawa Chrostowskiego w "C64+4 & AMIGA"? Przede wszystkim nasz kurs bëdzie nowoczeôniejszy. System operacyjny sië zmienia (no, ostatnio nieco wolniej, ale miejmy nadziejë, ûe to zastój chwilowy). Kurs z "Amigowca" bazowaî na systemie operacyjnym w wersji 1.3, my tymczasem mamy zamiar bazowaê na wersji 2.04 systemu, nie zapominajâc przy tym o systemach 2.1 i 3.0. Chcielibyômy to jeszcze raz podkreôliê: BËDZIEMY PISALI O OS 2.04+. Wiëkszoôê przykîadów (jeôli nie wszystkie) bëdzie wymagaê przynajmniej tej wersji systemu operacyjnego. Zaczniemy od tego, co z punktu widzenia uûytkowników jest najbardziej widoczne -- od graficznego interfejsu uûytkownika, tzn. ekranów, okien, gadûetów, menu. System operacyjny Amigi to jednak nie tylko okienka. Istnieje masa wielce przydatnych bibliotek nie zwiâzanych z GUI (Graphic User Interface -- Graficzny Interfejs Uûytkownika). Opiszemy wiëc "exec.library", czyli System Executor -- bibliotekë zarzâdzajâcâ caîym systemem, oraz "dos.library" -- bibliotekë zarzâdzajâcâ wysokopoziomowym I/O. Wîaôciwie to chcielibyômy po trochu opisaê wszystkie najwaûniejsze elementy systemu operacyjnego, aby daê Wam dobre rozeznanie w tym, co system jest w stanie programiôcie zaoferowaê. Chcielibyômy wiëc napisaê równieû o "amigaguide.library", "commodities.library", "workbench.library", "locale.library", "iffparse.library" itd. Sâ to, rzecz jasna, nasze poboûne ûyczenia, a czy te ambitne plany uda nam sië zrealizowaê, czas pokaûe. Jak juû wczeôniej wspomnieliômy, chcemy daê Wam "podstawy". Oznacza to, ûe NIE bëdziemy dokîadnie opisywaê wszystkich funkcji, pól struktur czy staîych. Jest to po prostu fizycznie niemoûliwe. System operacyjny jest tak obszerny, ûe jego peîny opis zajmuje tysiâce stron (mówimy o serii ksiâûkowej "Reference Manuals"). Z koniecznoôci wiëc bëdziemy opisywali tylko najwaûniejsze elementy systemu, najczëôciej uûywane w typowych programach. W tekôcie artykuîu znajdâ sië teû z pewnoôciâ pewne niedomówienia oraz póîprawdy -- chodzi po prostu o to, ûe gdybyômy zbyt czësto zastrzegali sië, ûe "nie do koïca jest tak, jak piszemy, bo...", to niezbyt dobrze obeznani z tematem Czytelnicy po prostu utraciliby gîówny wâtek artykuîu. Zagubiliby sië w tych wszystkich niuansach (albo zaczëliby sâdziê, ûe "ktoô" usiîuje ich "zrobiê w konia"); poza tym artykuî znacznie by sië wtedy wydîuûyî. Rzecz jasna, bëdziemy sië starali robiê jak najmniej bîëdów. Najprawdopodobniej wszystkie przykîady bëdâ intensywnie testowane przy uûyciu opisanych przeze mnie w Magazynie AMIGA 12/94--1/95 debuggerów. Jeûeli jednak znajdziecie w artykule bâdú w przykîadach jakieô bîëdy, lub teû macie inne uwagi/sugestie dotyczâce tego kursu, to piszcie do redakcji. Nie oczekujcie jednak, ûe Wasze listy znajdâ odzwierciedlenie juû w kolejnej czëôci kursu. Ze wzglëdu na dîugi cykl wydawniczy Magazynu AMIGA oraz na to, ûe piszemy z dwumiesiëcznâ "zakîadkâ", Wasze uwagi moûemy uwzglëdniê najwczeôniej 3 miesiâce po ich otrzymaniu. Inkludy Chcielibyômy skupiê sië na chwilë na "inkludach", czyli plikach nagîówkowych, doîâczanych przez kompilator dyrektywâ "#include". Na Amidze sâ one bardzo rozszerzone w stosunku do standardu ANSI -- zawierajâ wszystkie definicje i deklaracje niezbëdne do pisania aplikacji korzystajâcych z zasobów systemu operacyjnego. Istniejâ róûne wersje "inkludów" -- musicie mieê je przynajmniej w wersji dla OS 2.0, a w niektórych wypadkach potrzebne bëdâ inkludy dla OS 3.0 (my uûywamy inkludów dla OS 3.1 i Wam teû to polecamy -- moûna je znaleúê na dysku CD Freda Fisha bâdú w Internecie: serwer "ftp.rz.uni-wuerzburg.de", katalog "pub/amiga/frozenfish/bbs/cbm"). O strukturze inkludów powinniôcie wiedzieê tyle, ûe opisy "device'ów" znajdujâ sië w katalogu "devices", a bibliotek w katalogu "libraries" (nie zawsze -- duûe biblioteki majâ osobne katalogi, np. "exec", "intuition", "dos"). W katalogu "clib" znajdujâ sië prototypy (deklaracje) funkcji z poszczególnych bibliotek i niektórych device'ów. Twórcy kompilatorów tworzâ czësto dodatkowy katalog, o nazwie "pragmas" bâdú "inline", zawierajâcy pewne informacje umoûliwiajâce kompilatorom tworzenie bardziej efektywnych wywoîaï funkcji systemowych. Czasami tworzâ teû oni katalog "proto", zawierajâcy proste pliki powodujâce zaîadowanie jednym ruchem deklaracji i pragm, np. wykonanie w SAS/C "#include " powoduje doîâczenie "clib/intuition_protos.h" i "pragmas/intuition_pragmas.h". Niestety, nie we wszystkich kompilatorach tak jest. Niektóre nie majâ plików "proto" i trzeba "rëcznie" doîâczaê deklaracje i pragmy. Niektóre nie majâ równieû pragm -- wtedy doîâcza sië tylko deklaracje. Wydaje mi sië, ûe jak na wstëp, to ten fragment zrobiî sië to nieco przydîugi. Aby wiëc nie traciê czasu ani cennego miejsca, juû dziô zaczynamy "regularny" kurs. "Oddajë wiëc klawiaturë" w rëce mego wspólnika: "-- Aleû dziëkujë Kamilku za okazanâ mi îaskë w postaci wysîuûonej dyskietki, o otrzymaniu klawiatury nie ômiaîbym marzyê nawet skrycie." Co to jest multitasking? Multitasking jest to moûliwoôê wykonywania jednoczeônie (lub jeôli ktoô chciaîby byê dokîadny, prawie jednoczeônie) kilku programów. Taki system pracy komputera pozwala na peîniejsze wykorzystanie mocy procesora z dwóch zasadniczych powodów. Po pierwsze komputer domowy w wiëkszoôci wypadków czeka na sygnaî od uûytkownika lub urzâdzeï zewnëtrznych, w tym czasie inny program moûe efektywnie wykorzystywaê system (obciâûenie procesora da sië îatwo sprawdziê, np. za pomocâ programu Spy -- w graficzny sposób przedstawia on stopieï zajëcia procesora, czas, przez jaki pracowaî on "na peînych obrotach" oraz przez jaki "zbijaî bâki"). Drugim równie waûnym powodem budowy takich systemów jest moûliwoôê wspóîpracy kilku niezaleûnych programów, które mogâ na bieûâco przekazywaê sobie wyniki swojej pracy, a w ten sposób zaoszczëdziê czas potrzebny na zapis i odczyt danych z/do plików, co jest znaczâce przy wiëkszych obliczeniach. Taki sposób pracy jest szalenie wygodny. W tym wîaônie celu programy sâ wyposaûane w interface ARexxa (Amiga Rexx jest jëzykiem stworzonym w celu nadzorowania pracy programów (patrz Magazyn AMIGA 1/92, wrzesieï). Niestety, nie ma róûy bez kolców: z multitaskingiem trzeba uwaûaê. Piszâc programy naleûy pamiëtaê o tym, ûe podczas ich wykonywania mogâ sië znajdowaê w pamiëci inne programy. To jest nasz problem -- problem programistów, którzy muszâ pamiëtaê, ûe "nie sâ sami", ûe nie wolno "grzebaê" w nie swojej pamiëci oraz zmuszaê procesora do pracy, jeôli nie jest to konieczne. Zabronione jest tworzenie tak zwanych busy loopów, czyli wykonujâcych sië bez przerwy pëtli sîuûâcych do oczekiwania na informacjë (dokîadniej zajmiemy sië tym przy okazji opisu funkcji Execa Wait() oraz portów). Kolejnym problemem jest nieco wolniejsze funkcjonowanie programów, jednak twórcy borykajâ sië z nim raczej rzadko, poniewaû zastosowanie multitaskingu spowalnia dziaîanie programów w niewielkim stopniu (poza tym moûna programowi nadaê wyûszy priorytet, dziëki czemu bëdzie on miaî pierwszeïstwo w stosunku do pozostaîych). Jednak jeôli komuô zaleûaîoby na wyciôniëciu z maszyny wszystkiego, moûe wyîâczyê pozostaîe zadania (taski). Do tego celu przeznaczone sâ funkcje Execa (Forbid(), Permit()), jednak nie bëdziemy sië nimi zajmowali (przynajmniej na poczâtku). Amigowski multitasking jest doôê zgrabnie zorganizowany -- nawet jeôli dojdzie do katastrofy i jakiô program sië "powiesi", to nie oznacza to caîkowitej klëski systemu. Problem taki jest znany uûytkownikom programu Windows 3.1, który ma multitasking kooperatywny, czyli, mówiâc zîoôliwie, multitasking bez multitaskingu -- programy zwalniajâ procesor, gdy tego pragnâ, brak tam nadzorcy (patrz PC World Komputer Luty 1994: "Dos umarî!"). System zastosowany w Amidze wyglâda inaczej, powiedziaîbym, ûe jest pod wieloma wzglëdami lepszy. Na tym komputerze stale funkcjonuje program w trybie nadzorcy (Supervisor -- tryb procesora), zajmujâcy sië przydzielaniem czasu procesora programom znajdujâcym sië na liôcie oczekujâcych (ten program to taki komitet kolejkowy). Istnienie "wszechmocnego" nadzorcy pozwala na wykrycie i usuniëcie z listy zawieszonego programu, dziëki czemu system moûe dziaîaê nadal. W zasadzie mowa tu o anormalnym zachowaniu sië oprogramowania, jednak takie nieszczëôcia z caîâ pewnoôciâ spotkajâ Czytelników podczas pisania i testowania programów. Tyle wiedzy na temat multitaskingu powinno wystarczyê. Nareszcie moûemy sië zajâê bibliotekami, które sâ wypeînione po same brzegi funkcjami. Dlaczego biblioteki? Stosowanie bibliotek zewnëtrznych wynika z zastosowania multitaskingu. W wypadku pecetowego DOS-u funkcje znajdujâ sië w bibliotekach, które przy linkowaniu (konsolidacji) programu sâ doï doîâczane -- postëpowanie takie znacznie wydîuûa kod programu, a poza tym w wypadku funkcjonowania kilku programów jednoczeônie jest wprost zabójcze dla pamiëci (w wypadku Amigi równieû istniejâ takie biblioteki, ale czësto ich praca ogranicza sië do otwarcia zewnëtrznej biblioteki i wywoîania jakiejô jej funkcji). Biblioteki amigowe to wygoda i oszczëdnoôê -- spróbujmy to udowodniê. W chwili, gdy kilka programów korzysta z takiej samej funkcji, powiedzmy z file-requestera (okna wyboru plików), nie muszâ one mieê takiej funkcji w swoim kodzie -- wystarczy, ûe skorzystajâ z biblioteki systemowej "asl.library", która zawiera takâ funkcjë. Wykorzystywanie funkcji bibliotecznych oszczëdza równieû czas przeznaczony na pisanie i testowanie programów, poza tym dziëki zastosowaniu bibliotek programy sâ podobne do siebie zarówno pod wzglëdem obsîugi, jak i graficznego interfejsu uûytkownika (GUI). Spróbujmy sobie wyobraziê, ûe kaûde okno ma gadûet zamykania w innym miejscu, a zrozumiemy, co znaczy standard. Czëôê bibliotek znajduje sië w pamiëci staîej komputera (od systemu 2.0 jest tego 512 KB), pozostaîe biblioteki znajdujâ sië na dysku, przewaûnie w katalogu "LIBS:". Podstawowâ bibliotekâ jest "exec.library", bez jej udziaîu nie jest moûliwe funkcjonowanie wîaôciwie ûadnego programu. Biblioteka ta jest otwierana przy inicjacji systemu i pozostaje otwarta do koïca jego pracy. W jej zasobach znajdujâ sië funkcje sîuûâce do przydzielania pamiëci, otwierania innych bibliotek oraz wiele innych niezwykle poûytecznych narzëdzi. Ze wzglëdu na swój specyficzny charakter biblioteka Exec musi byê dostëpna dla kaûdego i w kaûdej chwili. Z tej wîaônie przyczyny, w przeciwieïstwie do pozostaîych bibliotek, nie ma potrzeby jej otwierania. Dlaczego otwieramy biblioteki? Biblioteka podczas otwierania jest umieszczana w pamiëci, jeôli pochodzi z dysku, jeôli natomiast pochodzi z ROM-u, to pozostaje w nim, a w pamiëci RAM zapisywana jest jedynie pomocnicza struktura opisujâca bibliotekë. W celu otwarcia biblioteki naleûy posîuûyê sië funkcjâ Execa: struct Library *OpenLibrary( UBYTE *libName, unsigned long version ); Pierwszym argumentem funkcji jest wskaúnik na nazwë biblioteki, drugim minimalna wymagana wersja biblioteki. Jeûeli funkcja odnajdzie ûâdanâ bibliotekë w odpowiedniej wersji, to zwróci adres opisujâcej jâ struktury "Library", w przeciwnym wypadku zwróci 0 (NULL). Dlaczego istnieje parametr ograniczajâcy wersjë biblioteki? Odpowiedú jest prosta: biblioteki rozrastajâ sië i majâ coraz wiëcej funkcji, programiôci sâ i czësto muszâ byê wybredni, wîaônie dlatego umiera system w wersji 1.3, a poprzednie juû zostaîy pochowane. Funkcja OpenLibrary w tej formie pojawiîa sië w systemie 1.2 -- wczeôniej istniaîa funkcja o tej samej nazwie róûniâca sië tym, ûe nie sprawdzaîa, jakâ wersjë biblioteki otwiera. Stara funkcja zostaîa zachowana dla utrzymania zgodnoôci systemu z juû napisanym oprogramowaniem -- obecnie nazywa sië OldOpenLibrary(), ma jedynie pierwszy argument. Wartoôê zwróconâ przez OpenLibrary() naleûy zapamiëtaê w zmiennej wskaúnikowej o ôciôle okreôlonej nazwie (np. IntuitionBase dla "intuition.library", ReqToolsBase dla "reqtools.library" itd.), poniewaû zmienna ta jest wykorzystywana przy wywoîaniach funkcji z danej biblioteki. Dlaczego zamykamy biblioteki? Kiedy otwarta przez nas biblioteka nie jest nam juû dîuûej potrzebna, czyli zwykle pod koniec programu, naleûy jâ zamknâê. Sîuûy do tego funkcja Execa: void CloseLibrary( struct Library *library ); Jako jej parametr naleûy podaê wartoôê zwróconâ przez OpenLibrary(), czyli wskaúnik na strukturë "Library". Poczâtkujâcy programiôci czësto majâ wâtpliwoôci, czy zamykanie bibliotek rzeczywiôcie jest potrzebne. Faktem jest, ûe jeûeli sië biblioteki nie zamknie, to nie bëdzie jakiejô strasznej katastrofy (nie dojdzie do zawieszenia programu), jednak porzâdny program ZAWSZE powinien zostawiaê po sobie porzâdek -- jeûeli sië coô (bibliotekë, czcionkë, plik, okno itd.) otworzyîo (bâdú utworzyîo), to naleûy to coô zamknâê, aby zapewniê sprawne dziaîanie systemu, umoûliwiê zwrot przydzielonej przy otwieraniu pamiëci. Proponujemy przeêwiczyê otwieranie i zamykanie bibliotek na przykîadzie -- Listing #1. W tym programiku otwieramy biblioteki, ich adresy przechowujemy w zmiennych o odpowiednich nazwach, po czym zamykamy biblioteki. Nie korzystamy jeszcze z ûadnych funkcji zawartych w bibliotekach (nie wszystko naraz). Tym, którzy dopiero zaczynajâ programowaê w C, naleûy sië drobne wyjaônienie odnoônie jednej z linii programu: if (GfxBase=(struct GfxBase*)OpenLibrary("graphics.library", 0)) Jëzyk C jest dosyê elestyczny i pozwala na jednoczesne przypisanie wartoôci i sprawdzenie, czy wartoôê ta jest róûna od zera. Z takimi jëzykowymi idiomami bëdziemy sië czësto spotykaê; dla "uîatwienia" bëdâ jeszcze wzbogacone o znak "!", czyli po prostu negacjë (UWAGA: niektóre kompilatory mogâ wygenerowaê ostrzeûenie o moûliwoôci wystâpienia bîëdu w wypadku takiej formy, jest ona jednak w peîni poprawna, a ostrzeûenia sâ po to, by odszukaê literówki -- '=' zamiast '=='). Podobnie naleûaîoby przypomnieê, co oznacza dziwolâg umieszczony poniûej, ale tym zajmiemy sië za chwilë. IntuitionBase=(struct IntuitionBase*)OpenLibrary... Struktura opisujâca bibliotekë Jak juû mówiliômy, podczas otwierania biblioteki otrzymujemy wskaúnik na strukturë "Library". Znajomoôê tej struktury nie jest moûe niezbëdna przy pisaniu programów, zawsze jednak warto wiedzieê dokîadnie, "co w trawie piszczy". Jednym z jej pól jest "lib_OpenCnt", w tym polu jest zapisana liczba uûytkowników korzystajâcych z biblioteki w danej chwili. Jeôli biblioteka straci wszystkich uûytkowników (pole lib_OpenCnt == 0), to moûe zostaê usuniëta z pamiëci i tak sië stanie, ale dopiero w wypadku braków pamiëci. Jeôli problemy braku pamiëci nie wystâpiâ, biblioteka bëdzie pozostawaê w pamiëci, pomimo iû nikt z niej nie korzysta (czeka na lepsze czasy). Przejdúmy do pól "lib_Version" i "lib_Revision". W polach tych zapisany jest numer wersji biblioteki. Wîaônie po tych polach moûna sprawdziê, z jakâ wersjâ systemu pracujemy. Patrz Listing #2. W kolejnych programach bëdziemy korzystaê z funkcji check_os(), której dla oszczëdnoôci miejsca nie bëdziemy za kaûdym razem przepisywaê, wiëc Czytelnik bëdzie zmuszony doîâczaê jâ (oraz definicje staîych "OS_xx") do kolejnych programów. Dwa sîowa odnoônie UWORD w deklaracji funkcji check_os() -- jest to nic innego jak "unsigned short int". Analogicznie ULONG oznacza "unsigned long int", a UBYTE -- "usigned char". W tym krótkim programiku pokazaliômy, jak moûna wykorzystaê zmiennâ "SysBase", która jest wskaúnikiem na strukturë "ExecBase" (wartoôê tej zmiennej nadaje doîâczony podczas linkowania programu moduî startowy, pobierajâc jâ z komórki pamiëci pod adresem 0x00000004 -- ta informacja jest waûna raczej dla programujâcych w asemblerze). Zawartoôê struktury "ExecBase" moûna poznaê analizujâc systemowe inkludy, a ôciôlej mówiâc, plik "exec/execbase.h". Pierwszym polem tej struktury jest "LibNode" typu "Library", co oznacza, ûe struktura ta jest rozbudowanâ wersjâ struktury "Library", dziëki czemu moûemy swobodnie zastosowaê rzutowanie typów (ang. casting), z którym spotkaliômy sië juû w pierwszym przykîadzie podczas przypisywania wartoôci zmiennym "IntuitionBase" i "GfxBase". Poza polem "LibNode" struktura "ExecBase" zawiera pewne specyficzne dla niej dane, takie jak np. adres obecnie wykonywanego zadania ("ThisTask"), typ procesora ("AttnFlags") oraz wiele innych, czësto prywatnych, informacji (tj. takich, których aplikacje nie powinny wykorzystywaê). Do danych zawartych w polu LibNode struktury "ExecBase" moûemy odwoîywaê sië na dwa róûne sposoby: ver=SysBase->LibNode.lib_Version; ver=((struct Library*)SysBase)->lib_Version; Analogicznie moûemy postëpowaê z pozostaîymi rozbudowanymi strukturami, opisujâcymi biblioteki: opc=IntuitionBase->LibNode.lib_OpenCnt; opc=((struct Library*)IntuitionBase)->lib_OpenCnt; Odwoîania te wskazujâ dokîadnie na të samâ zmiennâ, obie formy sâ poprawne. Powróêmy do struktury "ExecBase". Zapoznajmy sië z kolejnym przykîadem. Patrz Listing #3. Pole "ThisTask", jak juû wspomnieliômy, zawiera adres struktury "Task", w której znajdujâ sië informacje o wykonywanym w danej chwili zadaniu, a wiëc naszym programie. Informacji tych jest caîa masa (patrz "exec/tasks.h"), my pobieramy tylko te o nazwie procesu (bëdzie to najprawdopodobniej "Shell Process", choê mogâ sië zdarzyê i inne) oraz jego priorytecie (niemal zawsze 0). Komentarza moûe wymagaê uûyty w nim "for". Staîe symboliczne "AFB_68xxx" sâ zdefiniowane w pliku "exec/execbase.h". Staîa AFB_68010 ma wartoôê 0, AFB_68020 to 1 itd. Dane zawarte w polu "AttnFlags" sâ zapisane w formie maski bitowej; gdy jest obecny dany procesor, to bit o numerze "AFB_68xxx" jest ustawiony, ustawione sâ jednak równieû niûsze bity, tyczâce sië starszych procesorów -- z tego powodu zastosowaliômy pëtlë z licznikiem malejâcym, zaczynajâcâ sprawdzanie od najnowszych procesorów. Warunek "licznik==-1" bëdzie speîniony dla procesora MC68000, który nie jest odnotowany w "AttnFlags". Przykîad ten wyôwietli nieprawdziwe informacje dla procesora MC68060 (potraktuje go najprawdopodobniej jako MC68040), jako ûe odpowiedniej staîej brakuje w pliku "exec/execbase.h". Warto w tym momencie wspomnieê o róûnicy pomiëdzy staîymi "AFB_68xxx" i "AFF_68xxx": staîe "B" oznaczajâ NUMER bitu, a staîe "F" sâ gotowâ MASKÂ bitowâ (moûna by nieformalnie napisaê: "F"=1<<"B"). Radzimy o tym pamiëtaê, poniewaû jest to ogólnie uûywana konwencja, a pomylenie jednych staîych z drugimi staje sië przyczynâ bîëdnego dziaîania programu. Na tym koïczymy dzisiejszy odcinek i zapraszamy do lektury nastëpnej czëôci kursu. A za miesiâc bierzemy sië do okien, zajmiemy sië równieû informacjami pochodzâcymi od okna. Zalecana literatura: -- Inkludy (pliki dla kompilatora). -- AutoDoce (podzielony na poszczególne biblioteki i "device'y", przesortowany alfabetycznie suchy opis wszystkich funkcji systemu operacyjnego). -- "AMIGA ROM Kernel Reference Manual: Libraries, Devices" (przystëpnie napisany opis poszczególnych czëôci systemu operacyjnego, masa przykîadów). -- Brian W. Kerninghan, Dennis M. Ritchie "Jëzyk ANSI C", WNT, Warszawa, 1994.