Jazyk C pou₧φvß pro vyhodnocenφ logick²ch operßtor∙ tzv.
lenivΘ vyhodnocovßnφ, co₧ znamenß, ₧e se vyhodnotφ jen nejnutn∞jÜφ Φßst
logickΘho v²razu.
Pokud mßme nap°φklad logick² v²raz
v²sledek je v₧dy logickß pravda a je jedno co je
ulo₧eno v prom∞nnΘ a, nebo¥ operßtor logickΘho souΦtu pravda a cokoliv
je v₧dy pravda. Je tedy zbyteΦnΘ vyhodnocovat obsah prom∞nnΘ a, proto₧e na
jejφ hodnot∞ nezßle₧φ. A to je p°esn∞ to, co jazyk C d∞lß a Φemu °φkßme
lenivΘ vyhodnocovßnφ.
Podobn∞ se to mß s operßtorem logickΘho souΦinu (and):
v²sledek je v₧dy logickß nepravda a op∞t nezßle₧φ
na tom, jakou hodnotu mß prom∞nnß a.
Mo₧nß se zdß, ₧e znalost chovßnφ jazyka C je pro nßs
programßtory irelevantnφ, ale nenφ tomu tak (pokud by tomu tak bylo, tak bychom o tom
asi nepsali :-).
Uka₧me si n∞jak² k≤d:
// Deklarace n∞jakΘ struktury, kterß obsahuje
// jednu Φlenskou prom∞nnou.
typedef struct
{
int m_x;
} SOME_STRUCT;
void main()
{
// Definujeme prom∞nnou typu struktura
SOME_STRUCT oStruct;
// Definujeme prom∞nnou typu ukazatel na strukturu
// a zßrove≥
inicializujeme ukazatel
SOME_STRUCT *poStruct = &oStruct;
// Pokud je ukazatel inicializovßn
if (poStruct != NULL)
// a Φlenskß prom∞nnß je nastavena na deset
if (poStruct->m_x == 10)
// tak to mßme...
printf("Je to tak!\n");
} |
V tomto k≤du testujeme, zda je n∞jak² ukazatel na strukturu
inicializovßn a pokud ano, tak otestujeme, zda jejφ Φlenskß prom∞nnß je rovna
desφti. Tuto podmφnku se pokusφme zjednoduÜit:
// Pokud je ukazatel inicializovßn
// a Φlenskß prom∞nnß je nastavena na deset
if (poStruct != NULL && poStruct->m_x == 10)
// tak to mßme...
printf("Je to tak!\n"); |
Zamysleme se nad tφm, co by se stalo, kdyby jazyk C poctiv∞
vyhodnocoval cel² logick² v²raz a ukazatel poStruct byl nulov². Prvnφ Φßst
podmφnky je nepravdivß (z Φeho₧ plyne, ₧e cel² v²raz je nepravdiv²) a druhß
Φßst podmφnky zp∙sobφ pßd aplikace. ProΦ? Proto₧e se pokusφme p°istoupit na
adresu nula, kam ani nßhodou nesmφme. Jen₧e! ono to funguje, proto₧e jazyk C nenφ
pitomec a kdy₧ zjistφ, ₧e prvnφ Φßst v²razu s operßtorem and je
nepravdivß, dalÜφ vyhodnocovßnφ neprovßdφ. TΘto vlastnosti se
vyu₧φvß velmi Φasto, proto₧e to vede k p°ehledn∞jÜφm podmφnkßm (srovnejte si
ob∞ dv∞ podmφnky a doufßm, ₧e ta druhß se vßm lφbφ vφce).
DalÜφ ukßzka je spφÜe legrßcka a nidky jsem se s nφ u
cΘΦkov²ch program∙ nesetkal, ale b∞₧n∞ se pou₧φvß (alespo≥ v dokumentaci) v
jazyce PHP, kter² je velmi podobn² cΘΦku:
// N∞jakß funkce vracejφcφ 1 nebo 0.
// V naÜem p°φpad∞ v₧dy nula, Φφm₧ simulujeme chybu.
int Funkce()
{
printf("Vracim chybu...\n");
return 0;
}
// Funkce zapouzd°uje volßnφ funkce exit()
// a je zde kv∙li tomu, ₧e bude pou₧ita v
// logickΘm v²razu
int Konec()
{
exit(0); // Provede ukonΦenφ b∞hu programu
return 0; // tento return se ji₧ neprovede
}
void main()
{
// Volßnφ Funkce, kterΘ pokud sel₧e, vyvolß funkci Konec,
// kterß ukonΦφ program. Pokud se Funkce povede, vrßtφ
// hodnotu logickß pravda a dφky lenivΘmu vyhodnocovßnφ se
// funkce Konec volat nebude
a program pokraΦuje dßl.
Funkce() || Konec();
printf("Tak to je konec\n");
} |
D∙le₧it² je logick² v²raz, kter² je ve funkci main. Zde
se nejprve volß funkce Funkce, kterß vracφ logickou pravdu p°i ·sp∞chu (1)
a nepravdu (0) p°i selhßnφ. Chceme, aby po selhßnφ doÜlo k okam₧itΘmu ukonΦenφ
programu, kterΘ zajistφ funkce Konec. Pokud Funkce vrßtφ hodnotu
pravda, vyhodnocovßnφ se ukonΦφ, nebo¥ v²sledek je ji₧ dßn (logickß pravda) a
funkce Konec se nebude volat. Pokud funkce Funkce vrßtφ nepravdu, je
nutnΘ vyhodnotit i zbytek v²razu, zavolß se funkce Konec, kterß obsahuje
volßnφ funkce exit, kterß okam₧it∞ ukonΦφ b∞h programu.
Bohu₧el nem∙₧eme p°φmo psßt nßsledujφcφ v²raz:
proto₧e funkce exit nevracφ hodnotu a nelze ji tedy pou₧φt
v logickΘm v²razu. Z toho d∙vodu jsme zapouzd°ili volßnφ exit do funkce Konec,
kterß formßln∞ n∞jakou hodnotu vracφ. Formßln∞ proto, proto₧e k p°edßnφ
nßvratovΘ hodnoty ji₧ nedojde.
Zßv∞r
Mo₧nß bychom naÜli i dalÜφ fφgle, kterΘ vyu₧φvajφ lenivΘho
vyhodnocovßnφ logick²ch v²raz∙, a je tedy nutnΘ tuto vlastnost jazyka dokonale
ovlßdat. |