Variadické funkce jsou funkce s proměnným počtem parametrů. Variadické funkce mají povinné argumenty, těch je v každém zavolání stený počet, a volitelné argumenty, jejichž počet se může mezi voláními může lišit. Každá variadická funkce musí mít alespoň jeden povinný argument.
Zjištění počtu a typu volitelných argumentů uvnitř funkce se neděje automaticky, řeší se konvencí. Existují v zásadě tři přístupy.
V prvním předpokládáme pevný typ volitelných argumentů, v povinném argumentu předáváme jejich počet.
//hlavicka
double sum_of_doubles(int count, ...); // hlavicka
// volani
(3, 1.2, 2.2, 3.3); // vysledek je 6.6
sum_of_doubles(2, 2.1, 3.3); // vysledek je 5.4 sum_of_doubles
Ve druhém také předpokládáme pevný typ argumentů, ale poslední nepovinný argument má speciální hodnotu, například 0.
//hlavicka
int sum_of_ints(int first, ...); // hlavicka
// volani
(1, 2, 3, 0); // vysledek je 6
sum_of_ints(2, 2, 0); // vysledek je 4 sum_of_ints
Ve třetím přístupu předáme informaci o typech i počtu volitelných
argumentů pomocí povinných argumentů, příkladem takové funkce je
printf
.
K nepovinným argumentům přistupujeme pomocí maker z
stdarg.h
.
va_list
pro udržování nezpracovaných
argumentů,va_start
nastaví va_list
na všechny
volitelné argumenty,va_arg
vrátí hodnotu prvního argumentu ve
va_list
, potřebuje znát typ, první argument odstraní z
va_list
.va_end
ukončí práci s nepovinnými argumenty.Podrobnosti v následujících příkladech.
double sum_of_doubles(int n, ...)
{
va_list args;
double ret = 0;
(args, n); // tady se musi predat va_list a posledni povinny argument
va_start
for (int i = 0; i < n; i += 1)
{
+= va_arg(args, double); // tady se musi predat va_list typ argumentu
ret }
(args); // ukonceni prace s argumenty
va_endreturn ret;
}
//
// nutno volat aspon dvema argumenty !!!
// jinak UB
//
int sum_of_ints(int first, ...)
{
va_list args;
int ret = first;
(args, first);
va_start
while (1)
{
int val = va_arg(args, int);
if (!val) break;
+= val;
ret }
(args);
va_endreturn ret;
}
void almost_printf(char *format, ...)
{
va_list args;
int index = 0;
(args, format);
va_start
while(format[index])
{
switch(format[index])
{
case 'i':
("%i ", va_arg(args,int));
printfbreak;
case 'd':
("%f ", va_arg(args,double));
printfbreak;
}
+= 1;
index }
(args);
va_end}
Pozor, při předávání variadických argumentů dochází ke automatické
konverzi typů: float
je konvertován na double
,
char
a short
jsou konvertovány na
int
, jejich bezznaménkové varianty na
unsigned int
.
Navhněte strukturu pro komplexní číslo a naprogramujte variadickou funkci pro výpočet sumy komplexních čísel využívají prvního přístupu k určení počtu volitelných argumentů.
Napište funkci
long double prumer(char* format, ...)
, která výpočítá
aritmetický průměr ze zadaných hodnot různých datových typů. Typy
předávaných hodnot jsou určeny pomocí parametru format
,
který může tvořit libovolná posloupnost znaků odpovídající typům
následujících parametrů - i
pro typ int
,
d
pro typ double
a l
pro long
double.
Naprogramujte vlastní verzi funkce printf
určenou
pro tisk do string_builder
z druhého bonusového úkolu.
(Vyberte rozumnou část formátovacích primitiv, kterou chcete
podporovat). Hlavička funkce je tedy například
int sb_printf(char *format, ...)