* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Direktivy prekladace * * ========================================================================= * * sepsal: Mircosoft (http://mircosoft.mzf.cz) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tento soubor doporucuji otevrit primo v Turbo Pascalu a pri cteni prubezne konzultovat napovedu (umistete kurzor na dane slovo a stisknete Ctrl+F1). Vsechno, co zde najdete, jsem minimalne jednou vyzkousel a funguje to. Obsah: 1 - uvod (o co jde) 2 - prepinace {$neco+/-}: I,F,G,B,X,N,E,R,D,L 3 - ostatni direktivy (vkladani a linkovani souboru, nastaveni pameti, podmineny preklad) ****************************************************************************** 1 - uvod ****************************************************************************** Takze od zacatku: co to vlastne direktiva prekladace je? Je to informace pro prekladac (kompilator), urcujici nejake parametry prekladu. Pise se do zdrojoveho kodu, ale neni to prikaz, ktery by se pak provadel v programu. Ovlivni pouze preklad, ale ve vyslednem programu zkompilovana nebude. Direktivy se v Pascalu zapisuji takto: {$... ... }. Na prvni pohled vypadaji jako komentare, ale od tech se lisi tim, ze hned za znakem { nasleduje $ } (bez mezery!). Na miste prvnich tri tecek bude oznaceni direktivy (nekdy jen jedno pismeno, jindy cele slovo) a za nim pak parametry prislusne direktivy. Nezalezi na velikosti pisma. Direktiva muze byt bud globalni (dale budu znacit G) nebo lokalni (dale L). Rozdil je v tom, ze globalni direktiva se musi napsat jen jednou, uplne na zacatek zdrojaku (pred nebo za hlavicku, ale jeste pred Uses), zatimco lokalni se da vlozit kamkoli a i vickrat (jednou treba neco zapneme a pak to zase vypneme). Priklad globalni direktivy je treba prepinac {$X+/-} (rozsirena syntaxe), lokalni je treba prepinac {$I+/-} (kontrola operaci se soubory). ****************************************************************************** 2 - prepinace ****************************************************************************** Prepinace jsou direktivy, ktere neco zapinaji nebo vypinaji. Obecne vypadaji takto: {$?#}, kde misto '?' je nejake pismeno a misto '#' je bud '+' (zapni) nebo '-' (vypni). Takze napr.: {$I+}, {$R-} apod.. Kdyz potrebujeme nastavit vic prepinacu najednou, nemusime vypisovat pro kazdy z nich samostatnou zavorku, ale muzeme je sloucit do jedne: {$R+,X-,B-}, pocet prepinacu v jedne zavorce neni omezen. Vetsina prepinacu (mozna vsechny, nevim) dela totez, co se da nastavit v dialogu Options -> Compiler. Kdyz se podivate do napovedy (najedete na nejake zakrizkovavaci okenko a stisknete F1), vypise se vam popis, na co prislusna volba je. Takze na co direktivy, kdyz jde vsechno nastavit pres menu? Hlavne proto, aby bylo jiste, ze se vas program bude kompilovat na jakemkoli pocitaci nezavisle na mistnim nastaveni (direktivy maji pred nastavenim z menu prednost - pokud rikaji neco jineho nez menu, pouziji se ony). A take pro pripady, kdy potrebujete nejakou volbu v nekterem useku programu zapnout a v jinem zase zapnout, coz pres menu nejde. Pojdme se podivat na jednotlive prepinace podrobneji. Budu je radit od tech nejpouzivanejsich po ty nejmene pouzivane: {$I#} (L) - kontrola operaci vstup/vystup (prace se soubory) ============================================================== Urcuje zpusob, jakym se v programu budou vyhodnocovat I/O chyby. I/O chyba vznikne napr. kdyz zkousime otevrit neexistujici soubor pro cteni (reset), cist z nebo zapisovat do neotevreneho souboru, zavirat neotevreny soubor, zapisovat do souboru na uplne zaplnenem disku, cist ze souboru, kdyz uz jsme na jeho konci a podobne. Co se tedy stane: {$I+} - kdyz dojde k nejake I/O chybe, program se automaticky ukonci a na obrazovku se vypise prislusna chybova hlaska (napr. "File not open", "File not found" apod.). Do kodu programu bude zakompilovana automa- ticka kontrola po kazde provedene I/O operaci, ktera se o to postara. Funkce IOresult zde nefunguje (resp. vola se v ramci automaticke kontroly, takze uz nam je k nicemu). {$I-} - zadna automaticka kontrola do programu pridana nebude. Pokud se vyskytne I/O chyba, veskere dalsi I/O operace od te chvile budou ignorovany (neprovedou se), ale program kvuli tomu obvykle neskonci (pokud tim nevznikne nejaka uplne jina chyba). Pro rucni kontrolu I/O operaci v tomto rezimu slouzi funkce IOresult, ktera vraci bud hodnotu 0 v pripade, ze zatim vsechny I/O operace do tedka probehly bez chyby, nebo nenulovy chybovy kod, ktery rika, o jakou chybu slo. Volanim teto funkce se provede nasledujici: 1) Vrati se kod chyby nebo nula, kdyz je vse OK. 2) Pokud byla chyba, prislusna vnitrni promenna se vynuluje ("od tedka uz vse OK") a povoli se dalsi I/O operace. Pokud tedy zavolate IOresult dvakrat po sobe (a mezitim neprovedete zadnou I/O operaci), vrati podruhe vzdycky nulu. Pokud provedete nekolik I/O operaci a az pak zavolate IOresult, nebudete vedet, u ktere z nich pripadna chyba vznikla. I/O operace se po chybe ignoruji az do zavolani IOresultu, tak se vzdy ujistete, ze jste ji na konci jakehokoli useku prace se soubory zavolali, jinak by mohl I/O zustat zablokovany dost dlouho (a kdyz nas to nenapadne, vznikaji ukazkove zachvaty silenstvi :-) ). {$F#} (L) - vynuceni dalekeho volani procedur =================================================== Rozdil mezi blizkym a dalekym volanim spociva v tom, ze pri blizkem se vola jen pomoci ofsetu procedury (procedura je ve stejnem segmentu jako misto, odkud ji volame), zatimco pri vzdalenem volani se musi pouzit segment i ofset adresy (coz je trosku pomalejsi, ale casto je to nutne). {$F-} - Prekladac automaticky urcuje, ktery model pouzije. Pro procedury a funkce deklarovane v propojovaci casti jednotek (maji hlavicku v sekci Interface) se pouzije daleke volani (far) a pro ostatni (tj. deklarovane za Implementation bez hlavicky v Interface nebo v nejakem programu) se pouzije blizke (near). {$F+} - Vsechny procedury a funkce deklarovane od teto direktivy dal budou natvrdo far. Daleke volani je nutne pro ty procedury, ktere chceme volat pomoci promennych typu procedura (blize viz text o ukazatelich) a pro prekryvajici se programy (viz help ohledne overlay, ja se v tom nevyznam). Daleke volani se da zaridit take klicovym slovem far za hlavickou procedury, blizke pak slovem near. {$G#} (G) - generovani instrukci pro procesor 286 ===================================================== {$G-} - Prekladac je schopen prelozit jen instrukce pro 8086. {$G+} - Funguji i instrukce pro 80286 (napr. retezcove posilani dat na porty, bitove posuny a rotace o vic nez 1 a dalsi). Toto nastaveni vyuzijete jen pro useky psane v assembleru, protoze bezny Pascal si vystaci se standardni sadou instrukci. Kdyby se vam nekdy prekladac na nejakem "zelenem" (asm) useku zastavil s hlaskou "286/287 instructions are [ end ] not enabled", tak je proste direktivou {$G+} zapnete a je to. {$B#} (L) - vyhodnocovani logickych vyrazu az do konce ========================================================= {$B+} - Kdyz se v programu objevi nejaky logicky (boolean) vyraz slozeny z nekolika jinych, projde se vzdy az do konce. Napr. kdyz mame vyraz if (a>b)and(b>c) then neco, vyhodnoti se podminka a>b i b>c a kdyz plati obe dve, je vysledek true. {$B-} - Kdyz je v programu pri vyhodnocovani dlouhych vyrazu jasne, jaky bude vysledek, dal uz se nevyhodnocuje. Napr. kdyz v nasem vyrazu if (a>b) and (b>c) bude mit podminka a>b hodnotu false, je uz jasne, ze cely vyraz da hodnotu false bez ohledu na to, jestli druha podminka b>c plati nebo ne, a proto uz se program vyhodnocovanim druhe podminky nezdrzuje. Obvykle je kompletni vyhodnocovani vypnute (-). Hodi se napr. kdyz se logicky vyraz sklada z nekolika funkci, ktere potrebujeme vzdy vsechny zavolat. {$X#} (G) - povoleni nebo zakazani rozsirene syntaxe ======================================================== {$X-} - Rozsirena syntaxe je vypnuta, plati pravidla bezne pascalovske syntaxe. {$X+} - Rozsirena syntaxe je zapnuta. To znamena, ze se funkce (krome tech standardnich z jednotky System) muzou volat jako procedury (napr. pro cekani na stisk klavesy muzeme napsat Readkey; jako prikaz, i kdyz je to funkce - proste kdykoli, kdyz nepotrebujeme hodnotu, kterou funkce vraci, ale jenom nejake jeji "vedlejsi ucinky") a je umozneno pouzivani nulou ukoncenych retezcu z jednotky Strings (typ PChar). Kdyz prekladac narazi na volani funkce jako prikazu pri {$X-}, hlasi chybu "Invalid variable reference". {$N#} (G) - zpusob provadeni vypoctu s realnymi cisly ========================================================== {$N-} - Vsechny vypocty s pohyblivou desetinnou carkou se provadeji jen pomoci softwarovych prostredku a da se pouzivat jen typ Real. {$N+} - Na realne vypocty se pouzije numericky koprocesor (8087 nebo 80287) a daji se pouzivat jeste dalsi realne typy (Single, Double, Extended a Comp). Vypocty pres koprocesor jsou rychlejsi, takze pokud pouzivate realna cisla, tuhle volbu doporucuji zapnout. Ve vsech procesorech od 486 dal je koprocesor integrovany, takze se prakticky nemusite bat, ze by ho nejaky potencialni uzivatel vasich programu nemel. {$E#} (G) - emulace numerickeho koprocesoru ================================================== Tato volba ma prakticky vyznam jen pri zapnutem koprocesoru ({$N+}). {$E+} - K programu se prikompiluje knihovna pro softwarovou emulaci koprocesoru. Pokud pak program koprocesor v pocitaci, na kterem bezi, nenajde, emuluje ho. Vzhledem k tomu, ze posledni pocitace, ktere nemely kopr standardne zabudovany, byly 386ky, uz je tato volba celkem zbytecna (jenom se tim nafukuje EXE soubor). {$E-} - Zadna knihovna pro emulaci kopru se nepridava. Kdyby tato soucastka nahodou nebyla nalezena, program nepobezi. To uz ale dnes prakticky nehrozi. {$R#} (L) - kontrola rozsahu promennych ==================================================== Urcuje, jestli se do programu zakompiluje automaticka kontrola rozsahu. {$R+} - Do programu se zakompiluje automaticka kontrola rozsahu. Ta zahrnuje kontrolu hodnot, ktere prirazujeme promennym, hodnot promennych, ktere pouzivame jako indexy poli a podobne. Tim se program kapku zpomali, takze se doporucuje tento rezim pouzivat jen v nezbytnych pripadech (pri ladeni a hledani chyb). Pokud je nejaka hodnota mimo rozsah, program se ukonci s chybovou hlaskou "Range check error". {$R-} - Zadna kontrola se neprovadi. To znamena, ze pokud napr. vlozite do promenne hodnotu mimo jeji rozsah, vznikne nejspis chybny vysledek, ale pokud to nezpusobi nejakou fatalni chybu, program bezi klidne dal. Vypnuti kontroly rozsahu se nevztahuje na hodnoty konstant, ktere se vyhodnocuji jiz pri prekladu. Pokud mate napr. pole:array[1..8] of neco a chcete priradit pole[10]:=nejakou hodnotu, bude z toho chyba "Constant out of range", kterou vygeneruje prekladac, kteremu se nelibi index 10. Tato kontrola vypnout nejde. Ovsem kdyz napisete pole[i]:=neco, kde i je promenna s hodnotou treba 10, tak uz to prekladac sezere a kdyz si takhle neco zapisete "za" pole, je to na vasi zodpovednost (a pokud alokovana pamet pro pole neni v tu chvili vetsi nez deklarovany rozsah, skonci to hlaskou "Program provedl nepovolenou operaci a bude ukoncen"). {$D#}, {$L#} (G) - generovani informaci pro ladeni programu ============================================================== Pokud jsou tyto prepinace vypnute, nebudou do programu zabudovany ruzne informace uzitecne pro ladeni: tabulka s cisly radku a podobne, ktere umoznuji napriklad pousteni programu po krocich (klavesa F8) nebo i takove zdanlive samozrejmosti, jako ze kdyz program skonci chybou, bude kurzor tam, kde se ta chyba objevila. Takze pro vyvoj a testovani je dobre tyto volby zapnout (+) a az bude vse definitivne hotove a odladene, vypnout je, aby nezabiraly misto v EXE souboru. ****************************************************************************** 3 - ostatni direktivy ****************************************************************************** {$I soubor} (L) - vlozeni souboru ===================================== Na misto teto direktivy bude vlozen dany soubor, jako byste jeho obsah zkopirovali do schranky a vlozili sem. Vkladat se da jenom do deklaracni casti, ne mezi prikazy. Soubory se do sebe mohou takto vnorovat az 15nasobne. Priklad: {$I neco.pas} Pouziti: pokud chceme vlozit neco kratkeho, kvuli cemu nema cenu psat jednotku (nebo to chceme volat blizkym modelem volani) nebo pokud chceme nejak rozdelit rozsahlejsi kod do vice souboru. {$L soubor} - prilinkovani OBJ souboru do programu ====================================================== Umozni zakompilovat data primo do EXE souboru, takze pak nebude potreba tahat s programem datove soubory. Postup: 1) Soubor, ktery chceme vlozit, musime prevest do formatu, ktery to umoznuje, a to *.OBJ. To se provadi programem BINOBJ.EXE, ktery je obsazen v Turbo Pascalu: BINOBJ.EXE Zdroj Cil Identifikator Parametr Zdroj je jmeno souboru, ktery chceme prevest. Napr.: OBRAZEK.DAT. Parametr Cil urcuje jmeno vysledneho souboru. Koncovku dejte bud OBJ nebo zadnou (automaticky se doplni OBJ). Napr.: OBRAZEK.OBJ nebo jenom OBRAZEK. Parametr Identifikator urcuje jmeno, pod jakym se pak k datum v programu dostaneme. Napr.: Muj_obrazek. 2) Do zdrojoveho kodu vlozime nasledujici: procedure Identifikator; external; {$L Cil} Identifikator a Cil jsou ty same nazvy, ktere jsme si zvolili v predchozim kroku. Napr.: procedure muj_obrazek; external; {$L obrazek.obj} 3) To je vsechno. K datum se pak v programu dostanete jako k adrese te "jako procedury". Napr.: _putimage(x,y,50,50,addr(muj_obrazek)); (vyraz addr(muj_obrazek) nebo @muj_obrazek je hodnota typu ukazatel) Pokud to s mnozstvim prilinkovanych dat prezenete, prekladac vam vynada hlaskou "Code segment too large". {$M zasobnik, hromada_min, hromada_max} (G) - nastaveni velikosti pameti ============================================================================ Vsechna tri cisla jsou v bytech. Urcuji velikost pameti, kterou si pro sebe program zabere (program, ne jednotka - v ni tato direktiva nefunguje). Zasobnik ma obvykle 16384 B a da se teoreticky zvetsit az na 65536. Minimalni hodnotu je potreba vyzkouset (kdyz nebude stacit, program pri zapnute kontrole zasobniku {$S+} spadne). Tuto hodnotu je dobre (vlastne nezbytne) nastavit na co nejmensi, pokud ma byt program rezidentni, protoze jestli zabere cely zasobnik, uz pak nezbyde pro ostatni programy. Pro mensi programy staci jen nekolik malo kB. Pro hromadu se obvykle pouzije tolik pameti, kolik zbyde ze 640 kB zakladni pameti potom, co si z ni ukroji sve dily code segment, data segment a zasobnik, ale vzdy maximalne tolik, kolik je nastaveno jako hromada_max. Pokud pri spusteni programu zbyde na hromadu mene pameti nez je uvedeno v hromada_min, program bude automaticky ukoncen s chybovou hlaskou, ze je malo pameti. Obcas se to hodi: kdyz vim, ze muj program bude potrebovat X kB pameti na hromade, muzu tuto hodnotu specifikovat v direktive a pak uz se ve zbytku programu nezatezovat neustalym kontrolovanim Memavail pred kazdou alokaci, protoze mam jistotu, ze pamet stacit bude. Jestli ne, tak se program vubec nespustil a neni co resit. Priklad: {$M 16384,0,655360} (toto je obvykle nastaveni) Direktivy pro podmineny preklad ================================================== Ne vzdy potrebujeme prelozit cely program. Nekdy chceme vyradit ruzne casti, treba kontrolni vypisy pro ladeni atd.. Pro to se pouziva podmineny preklad. (vsechny tyto direktivy jsou lokalni) Vypinani a zapinani se provadi definovanim urcitych symbolu - slov: {$DEFINE symbol} (symbol je cokoli, co nas napadne; plati pro nej stejna pravidla jako pro bezne identifikatory) {$UNDEF symbol} (tohle symbol zase zrusi) Vlastni preklad se pak zapina nebo vypina pomoci: {$IFDEF neco} Tento text bude prelozen jen pokud je definovan dany symbol Neco. {$ENDIF} (tohle ukoncuje usek podmineneho prekladu) nebo obracene: {$IFNDEF neco} Tento text bude prelozen, pokud symbol Neco naopak neni definovan. {$ENDIF} nebo kombinace if-else: {$IFDEF neco} Prelozi se, pokud je Neco definovano. {$ELSE} Prelozi se, pokud Neco neni definovano. {$ENDIF} Symboly se daji globalne definovat i v menu: Options/Compiler/Conditional defines Dalsi moznost zapinani nebo vypinani prekladu je pomoci direktiv: {$IFOPT prepinac} napr.: {$IFOPT I-}, {$IFOPT X+} apod. Nasledujici text bude prelozen, pokud je dany prepinac v danem stavu. Usek podmineneho prekladu se ukoncuje opet direktovou {$ENDIF}. Vhodne napr. pro vyrazeni useku s rucni kontrolou IOresultem pri nastaveni {$I+}. ************************** a to je vse, pratele ****************************** (c) Mircosoft 17.1.2008