LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> C/C++ (25) - Funkce s proměnným počtem parametrů

Ukážeme si, jak napsat funkci síly printf, funkci kterou můžeme volat pokaždé s jinou sadou parametrů.

27.9.2005 07:00 | Jan Němec | Články autora | přečteno 24837×

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

Snad každého začínajícího programátora v jazyce C, který se alespoň zběžně seznámil s funkcemi a jejich implementací, zaujala funkce printf. Prvním parametrem je formátovací řetězec, kterým programátor určí počet, typ a způsob výpisu hodnot, ale další parametry jsou již nepovinné, nejrůznějšího druhu a může jich být (teoreticky) neomezený počet.

Jazyk C je nízkoúrovňový a založený na funkcích, takže asi již tušíte, že printf a jí podobné funkce s proměnným počtem parametrů nejsou jen jakousi výjimkou z jazyka se speciální implementací (jakou je třeba pascalská writeln) platnou pouze pro několik funkcí ze standardní knihovny, ale běžnou součástí jazyka. Programátor tak může vytvářet vlastní funkce s proměnným počtem parametrů.

V návrzích programovacích jazyků se nejčastěji objevují tři způsoby, jak umožnit uživateli volat funkci více způsoby.

  • Implicitní hodnota parametru
  • Přetížení funkce
  • Řešení typu printf

První dva způsoby standardní C nenabízí, ale setkáme se s nimi později u C++. Implicitní hodnota (posledního nebo několika posledních) parametrů se uvádí v hlavičce funkce a volající je může vynechat. V tom případě překladač sám doplní v místě volání (tedy nikoli v implementaci funkce) implicitní hodnoty. Ve skutečnosti je tedy na úrovní strojového kódu funkce volaná vždy stejně. Tato metoda se užívá všude tam, kde má několik posledních parametrů obvykle stejnou hodnotu a pouze výjimečně je programátor potřebuje změnit. Ve druhém případě, přetížení funkce, implementujeme dvě nebo více funkcí stejného jména (v C by došlo k chybě při linkování), ale různých parametrů a překladač při překladu volajícího kódu podle parametrů rozhodne, o jakou z několika stejnojmenných funkcí jde. Všimněte si, že ani jeden z obou způsobů neumožňuje implementovat funkci síly printf.

V případě typu printf se jedná i na úrovni strojového kódu skutečně o jednu funkci, která volající předá na zásobník pokaždé odlišnou sadu parametrů. Funkce nějakým způsobem (v případě printf z prvního parametru) zjistí kolik parametrů má a sama je ze zásobníku načte. Konkrétní způsob čtení ze zásobníku samozřejmě silně závisí na platformě, standardní knihovna proto nabízí makra, která umožňují psát podobné funkce přenositelné na úrovni zdrojového kódu.

Názornější to bude na příkladu. Ukážeme si funkci suma, která vrací součet všech svých nenulových parametrů typu int. Posledním parametrem je nula.

#include <stdio.h>
#include <stdarg.h>

int suma(int i, ...) {
  va_list p;
  int j;
  
  if (!i) return 0;
  va_start(p, i);
  do {
    j = va_arg(p, int);
    i += j; 
  } while (j);
  va_end(p);
  return i;
}

int main(void) {
  int i;

  i = suma(1, 2, 3, 4, 5, 0);
  printf("Suma je %i\n", i);
  return 0;
}

Makra a typy pro práci se zásobníkem jsou definovány ve standardním hlavičkovém souboru stdarg.h, pokud tedy chceme implementovat funkce s proměnným počtem parametrů, je třeba jej inkludovat. Tři tečky v hlavičce funkce suma jsou jen informací pro překladač, že funkce má libovolný počet parametrů a že ji má umožnit programátorovi volat různým způsobem. Typ va_list je jakýsi ukazatel na zásobník. Na běžných platformách by zřejmě stačil pro implementaci ukazatel na void, ale autoři jazyka C museli počítat i s různými divokými způsoby předávání parametrů funkci, proto zvolili samostatný typ. Pokud je již úvodní parametr 0, můžeme okamžitě vrátit 0, v opačném případě budeme v cyklu přičítat parametry. Voláním makra va_start nastavíme ukazatel p na zásobník těsně za první parametr i. Všimněte si, že funkce musí mít alespoň jeden parametr pevný, jinak by nebylo možné volat va_start. Makro se rozvine velmi zhruba na kód podobný

p = (void *) ((&i) + 1);

ale vše samozřejmě závisí na tom, jakým směrem roste zásobník, jak přesně jsou zarovnávány parametry, jak je definován va_arg atd., takže skutečná implementace může být podstatně složitější. Voláním

j = va_arg(p, int);

přiřadíme do j hodnotu dalšího parametru typu int a zároveň posuneme ukazatel p na případný další parametr. Pro představu, co asi va_arg vlastně dělá, uvedu i zde pokus o vlastní implementaci

j = *(int *) p;
p = (void *) (((char *) p) + sizeof(int));

ale ve skutečnosti bude (zejména kvůli zarovnávání na zásobníku) pravděpodobně kód rozvinutého makra va_arg složitější.

Na závěr je třeba ukončit práci se zásobníkem voláním va_end. Na platformách, kde je va_list vlastně obyčejným, byť maskovaným, ukazatelem a zásobník jen běžný blok paměti, se zpravidla va_end rozvine na vykonání prázdné akce. Jinde mohou být makra a typ va_list složitější a v těchto případech může provádět va_end nějakou nezbytnou akci, například uvolní paměť naalokovanou va_start a podobně.

Funkce s proměnným počtem parametrů v sobě skrývají některá úskalí. Především je třeba, aby funkce poznala počet a typ parametrů. Kdyby třeba volající funkce suma zapomněl na ukončovací nulu nebo volající printf napsal přebytečné znaky % do pevného parametru, bude funkce ze zásobníku vybírat neexistující parametry a chování takového programu není definováno. Dalším nebezpečím jsou implicitní konverze číselných typů. Zkuste ve funkci suma sčítat místo v intech v typu short, tedy zadat shorty jako parametry a ve funkci suma volat

j = va_arg(p, short);

Moje gcc 3.2 při překladu varuje

va.c: In function `suma':
va.c:11: warning: `short int' is promoted to `int' when passed through `...'
va.c:11: warning: (so you should pass `int' not `short int' to `va_arg')

a program skončí špatně (Segmentation fault). Na jiných překladačích může vše fungovat bez problémů. Příčina potíží je zřejmá. Typ short se při předávání zkonvertuje na int, neboť překladač (narozdíl od běžné funkce s pevným počtem parametrů) nezná požadovaný typ. Při přístupu na zásobník makrem va_arg ovšem získáváme short a to nemůže dopadnout dobře.

Pokračování příště

V příštím dílu začneme zběžně procházet standardní knihovnu. Nejdůležitější funkce už známe a standardní knihovna jazyka C je (například oproti javě) poměrně chudá a navíc ne všechny funkce se běžně využívají, takže nám toho již moc nezbývá.

Verze pro tisk

pridej.cz

 

DISKUZE

více výstupních bodů funkce 27.9.2005 10:58 camlost
|- Re: více výstupních bodů funkce 27.9.2005 11:09 Jan Němec
|- Re: více výstupních bodů funkce 27.9.2005 13:26 Aleš Hakl
| L Re: více výstupních bodů funkce 1.11.2005 14:13 camlost
L Re: více výstupních bodů funkce 3.10.2005 17:39 Jakub Jochec
Spis nez nejake flames by me osobne zajimalo toto... 3.10.2005 17:59 Jakub Jochec
|- Re: Spis nez nejake flames by me osobne zajimalo toto... 3.10.2005 18:17 Aleš Hakl
L Re: Spis nez nejake flames by me osobne zajimalo toto... 4.10.2005 08:08 Jan Němec
Jde to udělat líp ? 17.10.2005 19:08 Michal marwin
  |- Re: Jde to udělat líp ? 17.10.2005 23:49 Aleš Hakl
  L Re: Jde to udělat líp ? 1.11.2005 14:18 camlost




Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

16.7.2018 1:05 /František Kučera

Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.


Přidat komentář

18.6.2018 0:43 /František Kučera
Červnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 21. 6. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: F-Droid, aneb svobodný software do vašeho mobilu. Kromě toho budou k vidění i vývojové desky HiFive1 se svobodným/otevřeným čipem RISC-V.
Přidat komentář

23.5.2018 20:55 /Ondřej Čečák
Od pátku 25.5. proběhne na Fakultě informačních technologií ČVUT v Praze openSUSE Conference. Můžete se těšit na spostu zajímavých přednášek, workshopů a také na Release Party nového openSUSE leap 15.0. V na stejném místě proběhne v sobotu 26.5. i seminář o bezpečnosti CryptoFest.
Přidat komentář

20.5.2018 17:45 /Redakce Linuxsoft.cz
Ve čtvrtek 31. května 2018 připravuje webový magazín BusinessIT ve spolupráci s Best Online Média s.r.o. pátý ročník odborné konference Firemní informační systémy 2018. Akce proběhne v kongresovém centru Vavruška (palác Charitas), Karlovo náměstí 5, Praha 2 (u metra Karlovo náměstí) od 9:00 hod. dopoledne do cca 15 hod. odpoledne. Konference je zaměřena na efektivní využití firemních informačních systémů a na to, jak plně využít jejich potenciál. Podrobnější informace na webových stránkách konfrence.
Přidat komentář

14.5.2018 7:28 /František Kučera
Květnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 17. 5. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: Audio – zvuk v GNU/Linuxu.
Přidat komentář

7.5.2018 16:20 /František Kučera
Na stránkách spolku OpenAlt vyšla fotoreportáž Pražské srazy 2017 dokumentující srazy za uplynulý rok. Květnový pražský sraz na téma audio se bude konat 17. 5. 2018 (místo a čas ještě upřesníme).
Přidat komentář

17.4.2018 0:46 /František Kučera
Dubnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 4. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tématem tohoto srazu bude OpenStreetMap (OSM) aneb svobodné mapy.
Přidat komentář

16.3.2018 22:01 /František Kučera
Kulatý OpenAlt sraz v Praze oslavíme klasicky: u limonády a piva! Přijďte si posedět, dát si dobré jídlo a vybrat z mnoha piv do restaurace Kulový blesk, který najdete v centru Prahy nedaleko metra I. P. Pavlova na adrese Sokolská 13, Praha 2. Sraz se koná ve čtvrtek 22. března a začínáme v 18:00. Heslo: OpenAlt. Vezměte s sebou svoje hračky! Uvítáme, když si s sebou na sraz vezmete svoje oblíbené hračky. Jestli máte nějaký drobný projekt postavený na Arduinu, nějakou zajímavou elektronickou součástku, či třeba i pěkný úlovek z crowdfundingové akce, neváhejte. Oslníte ostatní a o zábavu bude postaráno.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

20.2.2018 18:48 / Ivan Majer
portal

20.2.2018 15:57 / Jan Havel
Jak využíváte služby cloudu v podnikání?

16.1.2018 1:08 / Ivan Pittner
verejna ip od o2 ubuntu

15.1.2018 17:26 / Mira Harvalik
Re: Jak udělat HTML/Javascript swiping gallery do mobilu?

30.12.2017 20:16 / Michal Knoll
odmocnina

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2018) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze