S funkcemi, které berou proměnný počet parametrů ("nerdy speaking", mají proměnnou aritu), už se zřejmě každý setkal (nejznámějším příkladem je dvojice funkcí scanf() a printf()). V C99 byla zavedena podpora i pro makra s proměnným počtem parametrů (variadic macros, někdy překládáno jako "variadická makra"). Jak taková věc vypadá a k čemu to lze použít se dozvíte v následujícím příspěvku.
Pokud explicitně neřeknu jinak, tak se v následujícím textu se budu věnovat pouze C99 (v C++ by měly být až od nového standardu C++0x, ale různé překladače toto samozřejmě implementují jako rozšíření).
Makra s proměnným počtem parametrů (MPPP) používají stejnou syntaxi pro vyjádření proměnnosti jako funkce -- výpustku (ellipsis). Ta znamená, že kromě pevně stanovených parametrů můžete předat makru libovolný další počet argumentů oddělených čárkami. Pro přístup k dodatečným argumentům v MPPP se používá makro __VA_ARGS__
, které se expanduje za argumenty předané v rámci výpustky. Je to tedy jednodušší přístup něž u funkcí, ale do jisté míry méně flexibilní (např. není umožněno snadné zjištění počtu předaných argumentů v rámci výpustky -- avšak existuje způsob, jak to zjistit).
Příklady použití
Kde se to dá použít? Uvedu dva příklady. Vemte si situaci, kdy chcete v rámci ladících výpisů vypisovat i název souboru a číslo řádku, na kterém výpis nastal. První, co vás napadne, je zřejmě následující:
#define debug(msg) fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg)
Co když ale budete chtít vypisovat i něco jiného, než řetězec (běžná záležitost)? Mohli byste uvažovat o použití inline funkce, ale zde byste nemohli přímo použít makra __FILE__
a __LINE__
(museli byste je předávat funkci jako parametry, což by bylo otravné). Řešením mohou být MPPP:
#define debug(...) fprintf(stderr, __VA_ARGS__)
Při tomto přístupu je pouze nutné dávat pozor na to, co makru předáváte. Musí to být formátovácí řetězec a argumenty dle tohoto řetězce. Např.
debug("%d, %d\n", var1, var2);
Druhý příklad je pro čistě dokumentační účely a používá se např. v knize Elements of Programming.
#define requires(...)
Tato konstrukce se pak používá u šablon k dokumentaci požadavků na typy. Cože, šablony v C? Kdepak, zde se mluví o C++. Bystrý čtenář ale jistě zaregistroval, že jsem psal, že v C++ MPPP nejsou. Ano, je tomu to. Kód v dané knížce spoléhá na rozšíření překladačů, že toto implementují (g++ vyhodí varování warning: anonymous variadic macros were introduced in C99
). V tomto případě to ale příliš nevadí, protože kód v knížce je určen především pro výukové účely a možnost jeho překladu je až druhořadá.
Závěr
Makra s proměnným počtem parametrů existují v C od C99 a v C++ jako rozšíření překladačů. Existují situace, ve kterých jejich použití má opodstatnění, ale obecně byste se měli snažit makrům vyvarovat a používat místo nich funkce/šablony, které mají typovou kontrolu (pokud ale špatně použijete funkce s proměnným počtem parametrů, tak vám ani typová kontrola nepomůže :)). A jako perličku na závěr bych uvedl, že v C++0x by nás měla čekat podpora i pro šablony s proměnným počtem parametrů (variadic templates).