Jazyk C umo₧≥uje vytvß°et funkce s prom∞nn²m poΦtem
parametr∙, co₧ je dost neobvyklß vlastnost. V tomto Φlßnku si ukß₧eme na
nebezpeΦφ, kterß na nßs Φφhajφ p°i programovßnφ a pou₧φvßnφ funkφ s
prom∞nn²m poΦtem parametr∙.
Nejprve si polo₧me otßzku, k Φemu vlastn∞ vytvß°et funkce s
prom∞nn²m poΦtem parametr∙. V n∞kter²ch chvφlφch je toti₧ v²hodnΘ vytvo°it
funkci, je₧ nemß dßn ani poΦet ani typy p°edßvan²ch parametr∙ a toto odlo₧it a₧
na oka₧ik volßnφ funkce. Typick²m p°φkladem m∙₧e b²t funkce printf a
jejφ varianty. Tato funkce oΦekßvß jako prvnφ parametr formßtovacφ °et∞zec a
dalÜφ parametry jsou volitelnΘ, co₧ nßm umo₧≥uje pou₧φvat funkci velmi voln²m
zp∙sobem. To se m∙₧e zdßt jako v²hodnΘ a ÜikovnΘ (no uvidφme pozd∞ji).
P°ed tφm, ne₧ se podφvßme na zmi≥ovanß nebezpeΦφ, zopakujme si
jak vytvß°et a pou₧φvat funkce s prom∞nn²m poΦtem parametr∙.
Pokud chceme mφt funkci s prom∞nn²m poΦtem parametr∙, uvedeme
v seznamu parametr∙ mφsto parametru t°i teΦky, kterΘ oznaΦujφ, ₧e dalÜφ
parametry jsou libovolnΘho typu a je jich libovoln² poΦet. Prom∞nn² poΦet parametr∙
musφ b²t uveden v₧dy jako poslednφ polo₧ka v seznamu formßlnφch parametr∙ a funkce
nesmφ obsahovat pouze polo₧ku prom∞nn² poΦet parametr∙. Pro p°φstup k parametr∙m
se pou₧φvajφ makra, kterß jsou definovßna v hlaviΦkovΘm souboru STDARG.H a jednß
se o nßsledujφcφ:
va_list |
Definice prom∞nnΘ p°edstavujφcφ seznam parametr∙. |
va_start |
Nastavφ adresu, kde zaΦφnß seznam parametr∙. |
va_end |
UkonΦφ prßci se seznamem parametr∙. |
va_arg |
Zφskß dalÜφ parametr ze seznamu parametr∙. |
Prom∞nnß p°edstavujφcφ seznam parametr∙ je ve skuteΦnosti
obyΦejn² ukazatel do pam∞ti zßsobnφku, kter² se nastavφ pomocφ makra va_start.
Makro va_end naopak nastavφ ukazatel na NULL. Makro va_arg posune ukazatel o poΦet
bajt∙ podle p°edanΘho typu. Tedy nic slo₧itΘho ani sv∞tobornΘho.
Jako jednoduch² p°φklad si uka₧me funkci Kalkul, kterß
bude pracovat jako sΦφtaΦka celoΦφslen²ch parametr∙. Tedy t°eba takto:
int Kalkul(int nCount, ...)
{
// Definice ukazatele na parametry
va_list pParams;
// Inicializace ukazatele
va_start(pParams, nCount);
int nSum = 0;
// Pro vÜechny parametry...
while (nCount)
{
// Zφskßnφ parametru a p°esun na dalÜφ parametr v seznamu
nSum += va_arg(pParams, int);
//
nCount--;
}
va_end(pParams);
return nSum;
}
void main()
{
// Volßnφ funkce se Φty°mi voliteln²mi parametry
int nSum = Kalkul(4, 1, 2, 3, 4);
} |
Samoz°ejm∞, ₧e bychom mohli vymyslet inteligentn∞jÜφ p°φklad,
ale dejme p°ednost jednoduchosti. Nynφ se podφvejme, jakß nebezpeΦφ na nßs
Φφhajφ.
ProblΘmem je, ₧e se nikde nekontroluje poΦet a typy skuteΦn²ch
parametr∙, m∙₧eme tedy volat funkci Kalkul nßsledovn∞ (a chybn∞):
// P°φliÜ mnoho parametr∙
nSum = Kalkul(2, 1, 2, 3, 4);
// Mßlo parametr∙
nSum = Kalkul(3, 1, 2);
// Parametry jsou jinΘho typu
nSum = Kalkul(2, "nic", "moc"); |
Ve funkci Kalkul se prost∞ oΦekßvajφ hodnoty typu int a je
jedno jakΘho typu jsou p°edanΘ parametry - funkce Kalkul je chßpe jako by to byla
celß Φφsla. Co₧ samoz°ejm∞ vede k nesprßvn²m v²sledk∙m a v n∞kter²ch
p°φpadech to m∙₧e vΘst a₧ k pßdu aplikace.
Je to zp∙sobeno tφm, ₧e prom∞nn² poΦet parametr∙ je realizovßn
pomocφ ukazatele do zßsobnφku, kter² se posouvß na dalÜφ hodnotu pomocφ makra va_arg
o dan² poΦet bajt∙. Podφvßme-li se na t°etφ p°φpad, tak zjistφme, ₧e na
zßsobnφk jsou krom∞ hodnoty 2 p°edßny ukazatele na °et∞zce. To ale ve funkci kalkul
nemßme Üanci zjistit, a proto₧e oΦekßvßme typ int, pracujeme ve
skuteΦnosti s adresami °et∞zc∙. V²sledkem souΦtu tedy bude souΦet adres obou dvou
°et∞zc∙.
DalÜφ problΘm nastßvß, pokud chceme p°edat hodnoty r∙zn²ch
typ∙. Pak musφme jako prvnφ parametr p°edßvat dalÜφ informace o parametrech (nejen
poΦet jako v Kalkul). Dobr²m p°φkladem pak m∙₧e b²t funkce printf a jejφ
formßtovacφ °et∞zec.
Jak je vid∞t, tak nev²hody v²razn∞ p°evyÜujφ v²hody, a proto si
myslφm, ₧e prom∞nn² poΦet parametr∙ je sice zajφmavß vlastnost jazyka C, ale
spφÜe teoreticky a v praxi bychom ji m∞li pou₧φvat pouze v nejnutn∞jÜφch
p°φpadech, kdy si nelze pomoc jinak.
A na samotn² zßv∞r malß otßzeΦka (°eÜenφ je v komentß°φch
ke Φlßnku):
// ProΦ to padß?
int x = 0;
scanf("%d", x); |
|