Učíme se C (24. díl) - Funkce s proměnným počtem parametrů - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



C/C++

Učíme se C (24. díl) - Funkce s proměnným počtem parametrů

ucime se jazyk C

25. dubna 2001, 00.00 | Definice funkcí s proměnným počtem parametrů, přístup k těmto
parametrům a makra hlavičkového souboru stdarg.h.

Funkce s proměnným počtem parametrů

Zatím jsme při programování v C byli zvyklí, že při volání funkce musí počet jejich skutečných parametrů odpovídat počtu parametrů formálních, tedy těch, které jsme určili v definici funkce. Ale kromě tohoto způsobu nabízí jazyk C i možnost definovat funkce, jejichž počet skutečných parametrů může být proměnný, což je nesporná výhoda oproti jazykům, které takovouto možnost nepodporují.

Definice funkce s proměnným počtem parametrů

Definice funkcí s proměnným počtem parametrů se od definicí normálních funkcí příliš neliší. Skutečnost, že funkce může mít různý počet skutečných parametrů dáme překladači najevo znaky tří teček na místě posledního parametru.

typ identifikátor_funkce(seznam_pevných_parametrů, ...)

Seznam pevných parametrů nelze vynechat, z čehož vyplývá, že každá funkce s proměnným počtem parametrů musí mít minimálně jeden pevný parametr. O něco níže se dozvíme, k čemu je vlastně dobrý.

Jako příklad si můžeme uvést hlavičku funkce pro součet libovolného počtu čísel.

int secti(unsigned int a, ...)

Asi se teď ptáte, jak vlastně lze k dodatečným parametrům z těla funkce přistoupit. Pro lepší pochopení celé problematiky bude lepší trochu blíže se podívat na konvence volání funkcí v jazyce C.

Konvence volání funkcí v jazyce C

To co nás bude hlavně zajímat, je způsob předávání parametrů. V okamžiku, kdy je Céčkovská funkce zavolána, hodnoty jejích skutečných parametrů jsou přeneseny do zásobníku, a to v opačném pořadí, než jak jsou při volání zapsány. Nejprve se tedy uloží poslední parametr. První argument funkce přijde na řadu až jako poslední, a je tedy až na vrcholu zásobníku. Nad ním jsou pak ještě vytvořeny lokální proměnné funkce. Důležité ale je, že překladač dokáže v zásobníku identifikovat všechny pevné parametry a přiřadit jim příslušné identifikátory. V jazycích jako je Pascal se skutečné parametry ukládají do zásobníku v pořadí jak jsou zapsány, takže při implementaci funkcí s proměnným počtem parametrů by mezi pevnými parametry (které by ležely někde níže v zásobníku) a lokálními proměnnými funkce (vrchol zásobníku) byla ještě oblast dat(dodatečné parametry), o které by nebylo známo jak je velká.

Každopádně, v C už máme přiřazeny identifikátory pevným parametrům a řešíme problém jak pracovat s daty předanými zbylými parametry. Opět je to část zásobníku, o které nevíme jak je velká. A právě teď nám poslouží pevné parametry, protože právě těmi programátor předává do těla funkce zprávu o tom, kolik a jaké nepovinné parametry ještě funkci předává. V případě naší funkce secti() bychom museli prvním parametrem předat počet dalších parametrů. Pokud bychom tedy chtěli sečíst čísla 3, 15, 6, a 7, zavolali bychom funkci takto: secti(4, 3, 15, 6, 7); První parametr, hodnota 4, tedy udává počet dodatečných parametrů.

Jiným příkladem může být například funkce printf(), která má také pouze jeden pevný parametr, řetězec, po jehož zanalyzování (zjištění počtu a typů popisovačů) je jasné, s kolika skutečnými parametry byla funkce volána a podle toho se pak řídí její další průběh.

S tím co už víme, můžeme konečně sestrojit tělo funkce secti():

int secti(unsigned int a, ...)
{ int i, soucet=0;
  int *p;

  p=(int*)(&a+1);
  for (i=0; i<a; i++) 
    { soucet += *p; 
      p++;
    }
  return soucet;        
}

Nejdůležitější částí kódu je inicializace pointeru p, který musí ukazovat za poslední pevný parametr, tedy na první přebývající parametr. Pak už je tento ukazatel v těle cyklu for jenom posouván na další parametry, které jsou přičítány k výsledné hodnotě soucet. V našem příkladu to máme jednodušší o to, že funkce secti() nepočítá s jinými parametry než typu int. Asi ale vidíte určité riziko, které je s funkcemi s proměnným počtem parametrů spojeno. Překladač totiž nemůže provádět typovou kontrolu, a proto se při volání funkce s nesprávným počtem či typem parametrů mohou vyskytnout chyby ve funkčnosti programu.

Makra hlavičkového souboru stdarg.h

Norma ANSI jazyka C pro zjednodušení a kvůli zajištění přenositelnosti (zásobník nemusí být na všech platformách implementován stejně) zavádí soubor stdarg.h, ve kterém jsou definována užitečná makra pro práci s proměnným počtem parametrů. Zavádí například datový typ va_list, což je vlastně jen obyčejný void ukazatel. Pro jeho inicializaci použijeme makro va_start, které tento ukazatel nastaví na začátek seznamu přebývajících parametrů.

va_start(p, lastparam)

p - ukazatel typu va_list, který bude inicializován
lastparam - poslední formální parametr funkce


Pomocí opakovaného volání makra va_arg (makro posouvá ukazatel p) získáme postupně hodnoty jednotlivých přebývajících parametrů.

va_arg(p, type)

p – již inicializovaný ukazatel typu va_list
type – identifikátor typu získávaného parametru.


Po přečtení všech parametrů bychom měli ukazatel p ještě deinicializovat pomocí makra va_end, které přiřadí pointeru p hodnotu NULL.

va_end(p)

Naše funkce secti() by tedy s použitím maker ze stdarg.h vypadala asi nějak takto:

int secti(unsigned int a, ...)
{ int i, soucet=0;
  va_list p;

  va_start(p, a);

  for (i=0; i<a; i++) soucet += va_arg(p, int); 
  va_end(p);

  return soucet;        
}

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » C/C++  

Diskuse k článku

 

Vložit nový příspěvek   Sbalit příspěvky

 

Zatím nebyl uložen žádný příspěvek, buďte první.

 

 

Vložit nový příspěvek

Jméno:

Pohlaví:

,

E-mail:

Předmět:

Příspěvek:

 

Kontrola:

Do spodního pole opište z obrázku 5 znaků:

Kód pro ověření

 

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: