Pokud sledujete náš seriál pravidelně, zřejmě víte, že v několika posledních článcích se zabýváme především problematikou nastavení překladače Borland Delphi. Vysvětlujeme si jednotlivé volby, jejichž zapnutím nebo vypnutím můžeme významně ovlivnit způsob, jakým bude vypadat (a jakým se bude chovat) výsledný spustitelný program.
V souvislosti s jednotlivými volbami vždycky najdeme nějaké téma, jehož podrobný a zevrubný rozbor zabere několik článků. Přestože si myslím, že většina z rozebíraných námětů je prakticky použitelná a užitečná, samotnému se mi začíná zdát, že popis voleb překladače začíná být poněkud rozvleklý :-)
Z toho důvodu, slibuji :-), se ho pokusím dokončit co možná nejrychleji; ideálně už v dnešním článku, v nejhorším případě v tom následujícím. Rád bych totiž otevřel pro změnu některé pokročilejší téma: popis překladače byl určen spíše začátečníkům, teď jsou tedy na řadě také pokročilejší programátoři. Prozatím nebudu prozrazovat, oč konkrétně půjde, ale bude se jednat o popis moderní technologie, která bude pro vás snad atraktivní.
Ať žije překladač
Pojďme se tedy vrátit k popisu překladače a jeho nastavení. Připomeňme, že veškerá nastavení, o nichž hovoříme (a o nichž budeme hovořit i v tomto článku), provádíme z hlavní nabídky Delphi volbami Project – Options, záložka Compiler.
Shrňme, které volby v nastavení překladače už máme za sebou:
- skupina Code generation: přepínač Optimization (slouží k zapnutí/vypnutí optimalizace, která se projeví vypuštěním nepotřebných proměnných z výsledného programu),
- skupina Code generation: přepínač Aligned recorded fields (slouží k zapnutí/vypnutí zarovnávání struktur v paměti do 32-bitových bloků),
- skupina Code generation: přepínač Stack frames (slouží k ovlivnění způsobu ukládání parametrů procedur a funkcí do zásobníku),
- skupina Code generation: přepínač Pentium-safe FDIV (slouží k zapnutí/vypnutí generování speciálního kódu odolného vůči chybě při dělení v plovoucí řádové čárce u starších procesorů Pentium),
- skupina Runtime errors: přepínač Range checking (slouží k zapnutí/vypnutí hlídání rozsahů proměnných),
- skupina Runtime errors: přepínač I/O chceking (slouží k zapnutí/vypnutí automatického testování chyb při vstupně/výstupních operacích, tj. především při práci se soubory),
- skupina Runtime errors: přepínač Overflow checking (slouží k zapnutí/vypnutí hlídání přetečení výsledků některých aritmetických operací. Rozdíl mezi Range checking a Overflow checking jsme si vysvětlili v předchozím dílu seriálu).
- skupina Syntax options: přepínač Strict var-strings (tato volba je funkční pouze v tom případě, že je vypnuta volba Open parametres. Používá se v souvislosti s řetězci typu ShortStrings – a to ještě jen v případě, že jsou parametry tohoto typu předávány do funkcí a procedur. Pokud je volba Strict var-strings zapnutá, hlídá překladač shodu formálních a skutečných parametrů.)
- skupina Syntax options: přepínač Complete boolean eval (použití tohoto přepínače předznamenává, jak budou v aplikaci vyhodnocovány logické údaje. Pokud je tento přepínač zapnutý, je vždy v logických výrazech vyhodnocena kompletní podmínka. V opačném případě je použito tzv zkrácené vyhodnocování.)
Jedeme dál
Tolik k obsahu minulých dílů. Nyní pojďme dál – k dalším přepínačům. Pokračujeme dalším přepínačem ve skupině Syntax options – přepínačem Extended syntax.
Skupina Syntax options: přepínač Extended syntax
Přepínač Extended syntax, který odpovídá direktivě překladače {$X}, nám umožňuje považovat volání funkcí za volání procedur. Důsledkem je možnost ignorovat návratové hodnoty funkcí. Kromě toho přepínač Extended syntax zapíná podporu datového typu PChar (což je v podstatě ukazatel na datový typ char).
Pojďme se podívat na příklad. Vytvořte v Delphi novou aplikaci a na formulář umístěte jedno tlačítko (Button). Pak ošetřete událost OnClick tohoto tlačítka takto:
procedure TForm1.Button1Click(Sender: TObject);
begin
VratMiCislo;
end;
Nyní ještě vytvoříme pomocnou funkci VratMiCislo, kterou voláme právě z výše uvedené obsluhy události Button1Click. Pro jistotu připomínám, že aby mohl být modul správně přeložen, musí být funkce VratMiCislo implementována před obsluhou události OnClick (v jejímž těle funkci voláme). Druhou možnost je použít klauzuli forward (tzv. dopřednou deklaraci):
function VratMiCislo: integer;
begin
ShowMessage(`Nyni vratim cislo`);
VratMiCislo := 25;
end;
Nyní aplikaci přeložte a spusťte:
- Standardně, tedy aniž cokoliv kdekoliv měníme, bude možné aplikaci spustit a nebude hlášeno žádné chybové hlášení. Aplikace jednoduše proběhne, funkce se zavolá a výsledek jejího běhu nikoho nezajímá. Nevzniká žádný problém.
- Pokud vypneme přepínač Extended syntax, bude při překladu projektu hlášena chybová hláška. Jejím důvodem bude skutečnost, že výslednou hodnotu funkce nikdo nepoužil, což je standardně chyba.
Přepínač Extended syntax máme obvykle zapnutý a nevypínáme jej.
Skupina Syntax options: přepínač Typed @ operator
Tento přepínač, který odpovídá direktivě {$T}, slouží k nastavení chování ukazatelů. Pokud je přepínač zapnut, říkáme, že ukazatel získaný operátorem @ je typovaný, tj. jde o ukazatel na nějaký konkrétní datový typ, například ukazatel na celé číslo, ukazatel na znak apod. A naopak: je-li přepínač Typed @ operator vypnutý, vrací operátor @ netypovaný, obecný ukazatel (pointer).
Jinak řečeno, pokud je tato volba vypnutá, je získaný ukazatel kompatibilní se všemi ostatními ukazateli. Jakmile tuto volbu zapneme, je vrácený ukazatel vždy kompatibilní jen s ukazateli na tentýž datový typ.
Skupina Syntax options: přepínač Open parameters
Přepínač Open parameters, který odpovídá direktivě překladače {$P}, je určen k povolení používání dlouhých řetězců jako parametrů funkcí. Tuto volbu bychom nikdy neměli vypínat, je zařazena především kvůli zpětné kompatibilitě. V této souvislosti si dovolím připomenout také přepínač Strict var-strings, který je též umístěn ve skupině Syntax Options.
Volby Strict var-strings a Open Parametres spolu spolupracují. Volba Strict var-strings je funkční pouze v tom případě, že je vypnuta volba Open parametres. Strict var-strings se používá se v souvislosti s řetězci typu ShortStrings – a to ještě jen v případě, že jsou parametry tohoto typu předávány do funkcí a procedur. Pokud však zapneme volbu Open parametres, nemá Strict var-strings prakticky žádný význam.
Ještě jednou však doporučím tuto volbu raději ignorovat a ponechat ji na stávající, přednastavené hodnotě.
Skupina Syntax options: přepínač Huge strings
Také volba Huge strings, která odpovídá direktivě {$H}, se týká řetězců a jejich používání v Delphi. Nastavení této volby totiž říká, jakým způsobem bude interpretován datový typ string.
Pokud je volba Huge Strings zapnutá a ve zdrojovém kódu použijeme datový typ string, bude ve skutečnosti (interně) použit datový typ AnsiString (což jsou dlouhé řetězce). Pokud volbu Huge Strings vypneme, bude klíčové slovo string odpovídat datovému typu ShortString, který odpovídá krátkým řetězcům (které se používaly v původním Pascalu a v úvodní verzi vývojového nástroje Delphi).
Pro úplnost snad jen dodejme informace o datových typech AnsiString a ShortString:
Datový typ |
Maximální délka řetězce |
Vyžadovaná paměť |
ShortString |
255 znaků |
2 až 256 bajtů |
AnsiString |
~2^31 znaků |
4 bajty až 2GB |
Skupina Syntax options: přepínač Asignable typed constants
Volba Asignable typed constants, která odpovídá direktivě překladače {$J}, je opět zařazena především kvůli zpětné kompatibilitě s Pascalem a s první verzí Delphi. K čemu slouží?
Nastavení tohoto přepínače ovlivňuje chování překladače v případě přiřazování do konstant s udaným typem. Konstanty s udaným typem jsou vlastně podobné inicializovaným proměnným a používají se například pro naplnění polí.
Pokud je volba Asignable typed constants zapnutá, znamená to, že s typovanými konstantami lze zacházet úplně stejně jako s běžnými proměnnými, tj. můžeme do nich za běhu programu přiřazovat různé hodnoty. Pokud přepínač vypneme, nebude možné do konstanty s udaným typem přiřadit žádnou jinou (novou) hodnotu – bude se jedna o konstanty v pravém slova smyslu.
Chcete-li, můžete si chování tohoto přepínače opět jednoduše prakticky vyzkoušet. Vytvořte v Delphi novou aplikaci, na formulář umístěte komponentu Button a ošetřete událost OnClick takto:
procedure TForm1.Button1Click(Sender: TObject);
const i: integer = 25;
begin
i := 3;
ShowMessage(IntToStr(I));
end;
Pokuste se aplikaci přeložit a spustit:
- Pokud bude zapnutý přepínač Asignable typed constants, překlad proběhne bez problémů a po klepnutí na tlačítko bude vypsána hodnota 3.
- Pokud ale bude tento přepínač vypnutý, při překladu bude ohlášena chyba na řádku I := 3 říkající, že do proměnné I nelze přiřadit.
Takto vypadá prakticky důsledek volby Asignable typed constants.
Tímto odstavce jsme dokončili předposlední skupinu přepínačů – skupinu Syntax options. Nyní se dostáváme k poslední skupině – ke skupině Debugging.
Skupina Debugging
Přepínače skupiny Debugging, na které se teď podíváme, slouží k nastavení takových parametrů překladače, které ovlivňují ladící informace. Tyto ladící informace pak využívá integrovaný debugger v případě, kdy potřebujeme program ladit.
Skupina Debugging: přepínač Debug information
Tento základní přepínač, který odpovídá direktivě {$D}, způsobí, že do vytvořeného souboru (DCU nebo DPU) budou přidány ladicí informace umožňující spouštět příslušnou aplikaci v integrovaném debuggeru.
Skupina Debugging: přepínač Local symbols
Přepínač Local symbols, který odpovídá direktivě {$L}, se týká lokálních symbolů a dalších odpovídajících informací.
Skupina Debugging: přepínače Reference info a Definitions only
Další přepínače ze skupiny Debugging, Reference info a Definitions only, které odpovídají direktivě {$Y}, jsou možná nejzajímavější. Jejich zapnutí totiž způsobí generování informací o symbolech potřebných pro nástroje jako například Code Browser, Code Explorer nebo Project Browser. Podívejme se na některé zajímavé kombinace nastavení těchto přepínačů:
- Pokud je Reference Info zapnutý a Definitions only také zapnutý, překladač uchovává informace o tom, kde je který identifikátor definován.
- Pokud je Reference Info zapnutý, ale Definitions Only vypnutý, překladač uchovává informace o tom, kde je který identifikátor definován a také kde je použit.
Tyto přepínače však mají vliv jen v případě, že oba předchozí přepínače (tedy Debug Information a Local Symbols) jsou zapnuté. To je velmi důležitá poznámka, jejíž opomenutí způsobí nefunkčnost voleb Reference Info a Definitions Only.
Skupina Debugging: přepínač Assertions
Přepínač Assertions, který odpovídá direktivě {$C}, generuje kód potřebný pro tzv. assertions, které si můžeme umísťovat do zdrojového kódu. Pokud jste assertions nikdy nepoužili, podívejte se na následující ukázku. Vytvořte novou aplikaci, na formulář umístěte komponentu Button. Ošetřete událost OnClick této události takto:
procedure TForm1.Button1Click(Sender: TObject);
var i: integer;
begin
i := 5;
ShowMessage(IntToStr(I));
assert(i = 5);
end;
Když nyní program spustíte, proběhne bez jakýchkoliv překvapení (vypíše číslovku 5). Zkuste však na řádku I := 5 udělat změnu, např.:
procedure TForm1.Button1Click(Sender: TObject);
var i: integer;
begin
i := 3;
ShowMessage(IntToStr(I));
assert(i = 5);
end;
Spustíte-li aplikaci nyní, vypíše se číslovka 3, a následně bude hlášena chyba – tzv. assertion failure, viz následující obrázek:
Pomocí těchto assertions (procedury assert) lze do zdrojového kódu umísťovat nejrůznější podmínky, jejichž splnění testujeme (a jejichž nesplnění považujeme za natolik závažné, že o něm chceme být jasně a důrazně informováni). Procedura assert neudělá nic v případě, že podmínka uvedená v jeho parametru je splněná; pokud však podmínka splněná není, vyhodí procedura Assert výjimku EAssertFailed.
Pro úplnost dodejme, že proceduře Assert můžeme předat ještě další parametr označující zprávu, kterou chceme v dané hlášce vypsat, například:
Procedura Assert je výhodná právě proto, že máme k dispozici přepínač Assertions (resp. direktivu {$C}. Takovýchto assertions totiž můžeme mít v kódu při ladění spoustu; jakmile jsme se přesvědčili, že už program funguje, vypneme přepínač Assertions a vygenerujeme verzi určenou k šíření. Volání procedury Assert se při vypnutém přepínači Assertions nijak neprojeví.
Na závěr
Tímto článkem jsme prozatím definitivně dokončili otázku překladu, překladače a jeho nastavení. Nevylučuji, že v budoucnu se k nastavení překladače (a píše linkderu) ještě vrátíme, ale v příštím díle už se budeme zabývat něčím jiným. Čím? Nechte se překvapit!