Hlavnφ
Hlavnφ strana
Seznam Φlßnk∙
NejΦten∞jÜφ Φlßnky
Progres e-mailem
Visual C++ FAQ

Serißly
COM
ISAPI

banner2.gif (2546 bytes)

Nenechte si ujφt
NeobdΘlnφkovß okna
Tisk bez Preview
MFC a DLL
Logo v MDI ploÜe
Kouzla s kombo-boxem
V²jimky v C++

banner.gif (3305 bytes)

Prom∞nn² poΦet parametr∙ funkce Radek Paviensk²
20.10.1999
[Hlavnφ strßnka]  |  [Rubrika]

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(41234);  
}

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(21234);
  // Mßlo parametr∙
  nSum = Kalkul(312);
  // 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);

PodobnΘ Φlßnky:

Kdo Otßzka nebo p°ipomφnka
paviensky@eternal.cz Odpov∞∩ na otßzku

Prohlφ₧enφ p°φsp∞vk∙ nebo nov² p°φsp∞vek

O firm∞... Kontakt Ostatnφ