Variadic makro - Variadic macro
A variadic makro je funkce některých počítačů programovací jazyky, zejména C preprocesor, přičemž a makro může být prohlášeno za přijímající různý počet argumenty.
Makra s proměnnými argumenty byla zavedena v roce 1999 v ISO / IEC 9899: 1999 (C99 ) revize C jazykový standard a v roce 2011 v ISO / IEC 14882: 2011 (C ++ 11 ) revize C ++ jazykový standard.[1] Byla přidána podpora pro variadická makra bez argumentů C ++ 20.[2]
Syntaxe deklarace
Syntaxe deklarace je podobná syntaxi variadické funkce: posloupnost tří plné zastávky "..."se používá k označení, že musí být předán jeden nebo více argumentů. Během rozšiřování makra každý výskyt zvláštního identifikátoru __VA_ARGS__ v seznamu nahrazení makra je nahrazen předanými argumenty.
Nejsou poskytovány žádné prostředky pro přístup k jednotlivým argumentům v seznamu proměnných argumentů ani pro zjištění, kolik jich bylo předáno. Je však možné zapsat makra, která spočítají počet předaných argumentů.[3]
Oba C99 a C ++ 11 standardy vyžadují alespoň jeden argument, ale protože C ++ 20 toto omezení bylo zrušeno prostřednictvím __VA_OPT__ funkční makro. The __VA_OPT__ makro je nahrazeno svým argumentem, pokud jsou argumenty k dispozici, a jinak je vynecháno. Běžné překladače také umožňují předávání nulových argumentů před tímto přidáním.[4][5]
Podpěra, podpora
Několik překladače podporovat makra s proměnnými argumenty při kompilaci kódu C a C ++: Sbírka překladačů GNU 3.0,[4] Zvonit (všechny verze),[6] Visual Studio 2005,[5] C ++ Builder 2006 a Studio Oracle Solaris (dříve Sun Studio) Forte Developer 6 aktualizace 2 (C ++ verze 5.3).[7] GCC také podporuje tato makra při kompilaci Cíl-C.
Podpora pro __VA_OPT__ bylo přidáno makro pro podporu nulových argumentů Sbírka překladačů GNU 8,[8] Zvonit 6,[9] ale zejména ne Visual Studio 2017.[10]
Příklad
Pokud printf
-jako funkce dbgprintf ()
bylo požadováno, což by jako argumenty bralo číslo souboru a řádku, ze kterého byl volán, platí následující řešení.
// Naše implementovaná funkceprázdnota realdbgprintf (konst char *Název_souboru, int Zdroj Lineno, konst char *CFormatString, ...);// Kvůli omezením podpory variadic maker v C ++ 11 následující// nekomplikované řešení může selhat a je třeba se mu vyhnout://// #define dbgprintf (cformat, ...) // realdbgprintf (__FILE__, __LINE__, cformat, __VA_ARGS__)//// Důvod je ten//// dbgprintf ("Hallo")//// rozšíří se na//// realdbgprintf (__FILE__, __LINE__, "Hallo",)//// kde čárka před uzavírací závorkou způsobí syntaktickou chybu.//// GNU C ++ podporuje nepřenosné rozšíření, které to řeší.//// #define dbgprintf (cformat, ...) // realdbgprintf (__FILE__, __LINE__, cformat, ## __ VA_ARGS__)//// C ++ 20 nakonec podporuje následující syntaxi.//// #define dbgprintf (cformat, ...) // realdbgprintf (__FILE__, __LINE__, cformat __VA_OPT __ (,) __VA_ARGS__)//// Použitím řetězce 'cformat' jako součásti variadic argumentů můžeme// obejít výše uvedené nekompatibility. To je složité, ale// přenosný.#define dbgprintf (...) realdbgprintf (__FILE__, __LINE__, __VA_ARGS__)
dbgprintf ()
pak lze nazvat jako
dbgprintf ("Ahoj světe");
který se rozšiřuje na
realdbgprintf (__SOUBOR__, __ČÁRA__, "Ahoj světe");
Dalším příkladem je
dbgprintf("% d +% d =% d", 2, 2, 5);
který se rozšiřuje na
realdbgprintf(__SOUBOR__, __ČÁRA__, "% d +% d =% d", 2, 2, 5);
Bez variadic maker, psaní obálky do printf
není přímo možné. Standardní řešení je použít stdargs funkčnost C / C ++ a mají volání funkce vprintf
namísto.
Koncová čárka
Při generování koncové čárky s prázdnými argumenty pro variadická makra existuje problém s přenositelností C99. Některé kompilátory (např. Visual Studio[5]) tiše odstraní koncovou čárku. Ostatní překladače (např .: GCC[4]) podpora uvedení ##
před __VA_ARGS__.
# define MYLOG (FormatLiteral, ...) fprintf (stderr, "% s (% u):" FormatLiteral " n", __FILE__, __LINE__, __VA_ARGS__)
Následující aplikace funguje
MYLOG(„Příliš mnoho bublin% u“, 42);
který se rozšiřuje na
fprintf (stderr, "% s (% u):" „Příliš mnoho bublin% u“ " n", __SOUBOR__, __ČÁRA__, 42);
což odpovídá
fprintf (stderr, "% s (% u): Příliš mnoho bublin% u n", __SOUBOR__, __ČÁRA__, 42);
Podívejte se ale na tuto aplikaci:
MYLOG("Pozornost!");
který se rozšiřuje na
fprintf (stderr, "% s (% u):" "Pozornost!" " n", __SOUBOR__, __ČÁRA__, );
který generuje syntaktickou chybu s GCC.
GCC podporuje následující (nepřenosné) rozšíření:
# define MYLOG (FormatLiteral, ...) fprintf (stderr, "% s (% u):" FormatLiteral " n", __FILE__, __LINE__, ## __ VA_ARGS__)
který odstraní koncovou čárku, když __VA_ARGS__ je prázdný.
Alternativy
Před existencí variabilních argumentů v C99 bylo zcela běžné používat dvojnásobně vnořené závorky k využití variabilního počtu argumentů, které mohly být dodány printf ()
funkce:
# definujte dbgprintf (x) realdbgprintf x
dbgprintf ()
pak lze nazvat jako:
dbgprintf ((„Dobrý den, svět% d“, 27));
který se rozšiřuje na:
realdbgprintf („Ahoj, svět% d“, 27);
Reference
- ^ Změny pracovních konceptů pro synchronizaci preprocesoru C99 - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm
- ^ „Vynechání čárky a vymazání čárky“. 12. července 2017. Citováno 14. června 2018.
- ^ Laurent Deniau (16. ledna 2006). „__VA_NARG__“. Diskusní skupina: comp.std.c. Usenet: [email protected].
- ^ A b C Variadic Macros - Using the GNU Compiler Collection (GCC)
- ^ A b C Variadická makra (C ++)
- ^ Změna zdrojového kódu Clang, která zmiňuje podporu __VA_ARGS__ (29. července 2006), všimněte si, že Clang byl otevřený v roce 2007. http://llvm.org/viewvc/llvm-project?view=revision&revision=38770
- ^ Porovnání funkcí Sun Studio - http://developers.sun.com/sunstudio/support/CCcompare.html
- ^ „Podpora C ++ 2a v GCC“. Citováno 14. června 2018.
- ^ "Podpora C ++ v Clangu". Citováno 14. června 2018.
- ^ „Oznámení: MSVC odpovídá standardu C ++“. 7. května 2018. Citováno 14. června 2018.