Umíme to s Delphi: 120. díl – logické výrazy a operátory v Delphi

Dnešní článek nejprve započne popisem některých dalších direktiv překladače, a pak se podrobně zaměří na zajímavou problematiku, které jsme se dosud vyhýbali: popíšeme si logické operátory v Delphi a podíváme se na způsob jejich vyhodnocování.

V dnešním článku budeme nejprve pokračovat v tématu, který je pro nás momentálně aktuální – budeme se zabývat dalšími přepínači a možnostmi v nastavení vlastností projektu.

Připomeňme, že změnou vlastností překladače nastavujeme výsledný vzhled přeloženého programového kódu. Jednotlivými přepínači můžeme snadno ovlivnit, jak se bude výsledný zdrojový kód chovat v případě vzniku chyb, v případě přetečení některých proměnných nebo výsledků operací, apod. Říkáme také, jakým způsobem bude výsledný programový kód optimalizován, tedy jak moc se má překladač prát s neefektivitami zanesenými do zdrojových kódů programátorem.

V předchozích částech seriálu jsme se postupně zabývali jednotlivými přepínači, přičemž jsme se vždy na delší čas zastavili u těch problémů, které s aktuálním překladačem přímo souvisí. V následujícím přehledu shrneme, co už máme za sebou – tedy které přepínače z nastavování projektu jsme již úspěšně vysvětlili.

Připomeňme, že veškerá nastavení, o nichž zde hovořím, se provádějí v dialogu Project – Options, na záložce Compiler.

Následující přepínače už jsme vysvětlili v předchozích článcích:

  • 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).

Jinak řečeno – úspěšně máme za sebou sekce Code generation a Runtime errors. Pokud se podíváte do zmíněného dialogu Project – Options, na záložku Compiler, snadno zjistíte, že k popisu nám zde zbývají dvě sekce: Syntax options a Debugging. Sekce Debugging se přímo týká integrovaného debuggeru a možností jeho nastavení, proto si ji necháme na konec a její popis spojíme s popisem integrovaného debuggeru a jeho jednotlivých parametrů. Nyní tedy zahájíme popis poslední zbývající sekce – sekce Syntax Options. Pojďme na to!

Sekce Syntax options

Sekce nazvaná Syntax Options slouží k nastavování některých voleb, které přímo souvisí se syntaxí zdrojového programu a s chováním výsledného kódu vzhledem k syntaxi zdrojáku. Uvidíte sami, že některé přepínače v této skupině jsou poměrně zajímavé a jejich nastavením můžeme poměrně výrazně ovlivnit způsob práce překladače – a potažmo také způsob běhu výsledného přeloženého programu.

Prvním přepínačem v sekci Syntax options je Strict var-strings.

Přepínač Strict var-strings

K čemu tento přepínač slouží? Nejprve si řekněme, že jeho zapnutí/vypnutí odpovídá direktivě překladače {$V}. Pokud nesledujete náš seriál pravidelně, raději zde připomenu, že každý z přepínačů lze ovládat i programově, pomocí zdrojového kódu, pomocí direktiv překladače {$X+}, resp. {$X-} pro zapnutí, resp. vypnutí přepínače X).

Vraťme se však k přepínači Strict var-strings. Tato volba je v podstatě zařazena jan kvůli zpětné kompatibilitě s Pascalem (a s Borland Delphi ve verzi 1). Tato volba je funkční pouze v tom případě, že je vypnuta volba Open parametres (viz níže). 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ů. Naopak pokud tuto volbu nezapneme (ponecháme vypnutou), je hlídání shody parametrů plně v rukou (a v kompetenci) programátora.

Přepínač Complete boolean eval

Přepínač Complete boolean eval je nesmírně zajímavý a jeho použití předznamenává, jak budou v apliakci vyhodnocovány logické údaje. Tento přepínač odpovídá direktivě překladače {$B}.

K čemu tento přepínač slouží a jak jeho nastavení ovlivní výsledné chování programu? Poměrně výrazně. Pokud je tento přepínač zapnutý, je vždy v logických výrazech vyhodnocena kompletní podmínka. Je tedy vyhodnocován kompletně celý logický výraz, i když už v průběhu vyhodnocování je jednoznačně rozhodnuto o výsledné hodnotě celého výrazu.

Naproti tomu pokud tuto volbu vypneme, bude vyhodnocování všech logických podmínek a výrazů probíhat jen do té doby, než bude u konkrétního výrazu nezvratně stanoven jeho celkový výsledek. Pak se vyhodnocování přeruší a zbývající části logického výrazu (které už nemohou mít vliv na celkový výsledek výrazu) tedy budou ignorovány.

Rád bych zdůraznil, že se zde zabýváme pouze logickými výrazy, tedy výrazy, jejichž výsledná hodnota může spadat pouze do jedné ze dvou možností – ano nebo ne (pravda nebo nepravda, jednička nebo nula). V případě aritmetických výrazů – a jakýchkoliv jiných dalších – samozřejmě postrádá tato direktiva smyslu.

Ve většině případů je tento přepínač vypnutý. Takové je také standardní implicitní nastavení překladače. V takovém případě se používá zmíněné zkrácené vyhodnocování logických výrazů, které spočívá v tom, že vyhodnocování probíhá jen do toho okamžiku, než je definitivně stanoven výsledek výrazu, pak se přeruší.

Protože jsme se logickými výrazy v našem seriálu vlastně ještě nezabývali, věnujeme zbytek dnešního článku právě jejich popisu. Nejprve se podíváme na logické výrazy obecně, pak se budeme zabývat způsobem jejich vyhodnocování.

Logické výrazy v Delphi

Každému je asi jasné, že na rozdíl od praktického života platí při programování velmi často následující pravidlo: neexistuje nic mezi pravdou a nepravdou. Není žádný mezistav ve smyslu „nevím “,„možná “,„pravděpodobně “.

Program (skoro) nikdy není posloupnost příkazů, které se provádí postupně jeden za druhým tak, jak jsou uspořádány, dokud není konec. Někdy je totiž nutné určitou část přeskočit (neprovést), jinou zopakovat, atp. Program se rozběhne, provede nějaké inicializace –ale dříve či později nastane okamžik, ve kterém se bude muset o svém dalším postupu rozhodovat. Toto rozhodnutí může přijít na základě uživatelovy volby, ale také třeba na základě vypočteného výsledku nebo na tom, zda bylo při čtení diskového souboru dosaženo jeho konce. A to jsou přesně situace, ve kterých se uplatňují ony dvě zmíněné logické hodnoty: pravda a nepravda.

Tohle jistě našeho čtenáře nijak nepřekvapí. A co z toho všeho plyne? Jediný důsledek – logický výraz. Logický výraz je takový výraz, jehož pravdivost lze jednoznačně vyhodnotit s jedním ze dvou možných výsledků: pravda (true) a nepravda (false). A podle toho, jakou hodnotu takový výraz zrovna má, se rozhoduje o mnoha činnostech v programu.

Řekli jsme si, že logický výraz může nabývat právě jedné z hodnot – pravda a nepravda. Často nám nestačí vědomí, že nějaký výraz má tuto pravdivostní hodnotu, potřebovali bychom (tuto hodnotu) někam uložit, někde si ji uchovat. V programovacím jazyku Pascal – na rozdíl třeba od jazyka C, kde se logické hodnoty uchovávají v celočíselných proměnných typu int) – existuje datový typ Boolean určený právě a jen pro uchovávání logických hodnot true/false (pravda/nepravda).

Abychom mohli vytvářet logické výrazy, potřebujeme (stejně jako u aritmetických výrazů) operandy a operátory. Zatímco operandy jsou v obou druzích výrazů stejné (jsou to proměnné, volání funkcí, konstanty apod.), logické operátory tvoří zvláštní skupinu. Pravdivost logických výrazů, které jejich pomocí vytváříme, se řídí základními pravidly Booleovy algebry, nicméně v následující tabulce naleznete jejich stručný nástin:

Logický operátor Význam Typ operátoru (počet operandů) Na jaké operandy (datové typy) lze aplikovat Vzniklý výraz je pravdivý, když...
= Porovnání – rovnost Binární jednoduché, třídy, odkazy na třídu (class reference), rozhraní (interface), string, packed string když jsou oba operandy shodné
<> Porovnání - nerovnost Binární jednoduché, třídy, odkazy na třídu (class reference), rozhraní (interface), string, packed string nejsou-li oba operandy shodné
and Logický součin Binární Logické (Boolean) jsou-li oba operandy pravdivé
or Logický součet Binární Logické (Boolean) je-li pravdivý alespoň jeden z operandů (nebo oba)
xor Exkluzivní logický součet Binární Logické (Boolean) jsou-li hodnoty operandů různé
not Negace Unární Logické (Boolean) původní výraz byl nepravdivý
< Menší než Binární jednoduché, string, packed string, PChar levý operand je menší než pravý
<= Menší nebo rovno Binární jednoduché, string, packed string, PChar levý operand je menší než pravý nebo jsou si oba operandy rovny
> Větší než Binární jednoduché, string, packed string, PChar levý operand je větší než pravý
>= Větší nebo rovno Binární jednoduché, string, packed string, PChar větší nebo rovno Binární levý operand je větší než pravý nebo jsou si oba operandy rovny

Než si ukážeme několik příkladů na logické výrazy, ukážeme si alespoň zjednodušeně způsob jejich vyhodnocování. Dejme tomu, že hodnota a je rovna 10 a hodnota b je rovna 15. Dále máme následující výraz:

((a <> b) and (a < 25)) or not(a = b)

Když počítač tento výraz vyhodnocuje, postupuje zhruba takto:

  • (a <> b) je pravda, protože a (rovnající se 10) je různé od b (rovnající se 15). Tento podvýraz (a <> b) označme A.
  • (a < 25) je pravda, protože a je menší než 25. Tento výraz označme B .
  • (A and B) je pravda, protože logickým součinem dvou pravdivých výrazů vznikne opět pravdivý výraz. Můžete si to představit také jako „pravda a zároveň pravda je pravda“. Tento výraz označíme C .
  • (a = b) je nepravda, protože a není rovno b. Tento výraz označme D .
  • not D je pravda, protože D byla nepravda.
  • C or D je pravda, protože logickým součtem dvou pravdivých výrazů dostaneme opět pravdivý výraz („pravda nebo pravda je zase pravda“).

Protože poslední vyhodnocovaný výraz (C or D) byl pravdivý (a do jeho vyhodnocení jsme postupně zahrnuli vyhodnocení všech jeho „podvýrazů“), je zřejmé, že celý původní výraz (tj. ((a <> b) and (a < 25)) or not(a = b) je pravdivý – tedy v případě námi předpokládaných hodnot a ,b. Pro jiné hodnoty může být samozřejmě situace opačná.

Pojďme si ukázat tři příklady logických výrazů i s jejich pravdivostní hodnotou (viz následující tabulka). Předpokládejme, že hodnota a je rovna 10 a hodnota b je rovna 15:

Logický výraz Jeho pravdivostní hodnota Důvod
a = b False (tj. nepravda) neplatí, že a je rovno b
(a <> b) and (a < 25) True (tj. pravda) platí, že a není rovno b, dále platí, že a je menší než 25, a nakonec platí, že pravda and pravda je pravda
(a – 10 <> b) or (b > 3) True (tj. pravda) platí, že a – 10 není rovno b, dále neplatí, že b je větší

než 3, ovšem pravda or nepravda je nakonec pravda

Zopakujme tedy,že pomocí logických operátorů konstruujeme logické výrazy a ty jsou jedním ze základních kamenů např. pro rozhodování o dalším průběhu (tzv.větvení) programu.

Způsob vyhodnocování logických výrazů v Pascalu

Nyní se pojďme podívat na to, jak jsou logické výrazy v Pascalu (a tedy v Delphi) vyhodnocovány. Standardní nastavení, jak jsme si řekli v úvodu článku, spočívá v zapnutém zkráceném vyhodnocování.

Logický součin (and) a součet (or) se vyhodnocuje tak, že argumenty jsou postupně vyhodnocovány zleva doprava, ale jakmile je možné určit konečný výsledek, vyhodnocování se okamžitě ukončí.

Nyní si ukážeme několik příkladů a popíšeme způsob jejich vyhodnocování. Proměnné i , j, k jsou logické (datový typ Boolean).

Hodnoty proměnných: i = True, j = True
Výraz: k := i and j;
Vyhodnocení: Proměnná i obsahuje pravdu, j je také pravda a logickým součinem dvou pravd dostaneme opět pravdu. Do proměnné k tedy bude přiřazena hodnota True.

Hodnoty proměnných: i = False, j = True
Výraz: k := i and j;
Vyhodnocení: Proměnná i obsahuje nepravdu, j je pravda a logickým součinem pravdy a nepravdy vznikne nepravda, takže do k bude přiřazena hodnota False.

Hodnoty proměnných: i = True, j = True
Výraz: k := (i and j) or (i = True);
Výsledek: Vyhodnocování začne výrazem (i and j). Protože i a j jsou pravdivé, je tento výraz pravdivý. Vzhledem k tomu, že tento výraz je součástí logického součtu (následuje or), a tedy je v tomto okamžiku již zřejmé, že celkový výsledek bude pravda, vyhodnocování se ukončí a k dalšímu výrazu (i = True) se vůbec nedostane. Výsledkem bude přiřazení True do proměnný k.

Hodnoty proměnných: i = False, j = True
Výraz: k := (i and j) or (i = True);
Výsledek: Vyhodnocování opět začne výrazem (i and j).Protože i je nepravdivé, je tento výraz nepravdivý. Pokračuje se však dalším vyhodnocováním, protože není dosud znám výsledek celého výrazu. Výraz (i = True) je pravdivý. Celý výraz je tedy pravdivý (nepravda nebo pravda je pravda), což je stejný výsledek jako v předchozím případě, k jeho získání však bylo nutné vyhodnotit celý výraz.

Tolik pro dnešek k příkladům na zkrácené vyhodnocování. Za týden budeme pokračovat některými dalšími příklady, na nichž bude z praktického hlediska lépe vidět, jaké výhody (a také těžkosti) nám může přinést zapnuté/vypnuté zkrácené vyhodnocování.

Na závěr

Dnešní článek byl zaměřen na problematiku logických výrazů a způsobu jejich vyhodnocování. Protože jsme opět zabředli do poměrně podrobného teoretického popisu některých pravidel a operátorů, nestihli jsme v článku popsat to, co jsem původně zamýšlel – totiž princip zkráceného vyhodnocování a jeho praktické dopady v konkrétních příkladech. Z toho důvodu se za týden k vyhodnocování logických výrazů ještě vrátíme a ukážeme si, jakým způsobem můžeme zkrácené vyhodnocování využít a zaintegrovat jej jako součást aplikační logiky.

A také si samozřejmě ukážeme, jak nám může zkrácené vyhodnocování zkomplikovat život. Prozatím doufám, že vám dnešní shrnutí logických operátorů bylo ku prospěchu.

Diskuze (4) Další článek: IBM pracuje na MS Office pro Linux

Témata článku: Software, Programování, Překladače, Fields, Pascal, DEL, Nota, Log, Zvláštní význam, Stejný výsledek, Díl, Vypnutí, Dnešní shrnutí, Syntax, Opera, Algebra, Options, Praktický život, Operátor, Jednoduchý typ


Určitě si přečtěte



Aktuální číslo časopisu Computer

Speciál o přechodu na DVB-T2

Velký test herních myší

Super fotky i z levného mobilu

Jak snadno upravit PDF