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 28989×
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ý
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
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
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
|
Příspívat do diskuze mohou pouze registrovaní uživatelé.
|
|
![>](img/sipka2.png)
Vyhledávání software
![>](img/sipka2.png)
Vyhledávání článků
28.11.2018 23:56 /František Kučera Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1
12.11.2018 21:28 /Redakce Linuxsoft.cz 22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář
6.11.2018 2:04 /František Kučera Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
4.10.2018 21:30 /Ondřej Čečák LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář
18.9.2018 23:30 /František Kučera Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
9.9.2018 14:15 /Redakce Linuxsoft.cz 20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business.
Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář
12.8.2018 16:58 /František Kučera Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář
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ář
Více ...
Přidat zprávičku
![>](img/sipka2.png) Poslední diskuze
31.7.2023 14:13 /
Linda Graham iPhone Services
30.11.2022 9:32 /
Kyle McDermott Hosting download unavailable
13.12.2018 10:57 /
Jan Mareš Re: zavináč
2.12.2018 23:56 /
František Kučera Sraz
5.10.2018 17:12 /
Jakub Kuljovsky Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?
Více ...
|