Article de reference

macro variadique

Une macro variadique est une caractéristique de certains langages de programmation informatique , notamment le préprocesseur C , selon laquelle une macro peut être déclarée pour...

Une macro variadique est une caractéristique de certains langages de programmation informatique , notamment le préprocesseur C , selon laquelle une macro peut être déclarée pour accepter un nombre variable d' arguments .

Les macros à nombre variable d'arguments ont été introduites en 1999 dans la révision ISO/IEC 9899:1999 ( C99 ) de la norme du langage C , et en 2011 dans la révision ISO/IEC 14882:2011 ( C++11 ) de la norme du langage C++ . La prise en charge des macros variadiques sans argument a été ajoutée dans C++20 et C23 .

C/C++

void debugPrint ( const char * fichier , int ligne , const char * fmt , ...);

En raison des limitations de la prise en charge des macros variadiques en C++11, la solution simple suivante peut échouer et doit donc être évitée :

#define dbgprintf(cformat, ...) debugPrint(__FILE__, __LINE__, cformat, __VA_ARGS__)

La raison est que

dbgprintf ( "Bonjour" )

s'étend à

debugPrint ( __FILE__ , __LINE__ , "Bonjour" , )

où la virgule avant l'accolade fermante entraînera une erreur de syntaxe.

GNU C++ prend en charge une extension non portable qui résout ce problème :

#define dbgprintf(cformat, ...) debugPrint(__FILE__, __LINE__, cformat, ##__VA_ARGS__)

C++20 prend en charge la syntaxe suivante.

#define dbgprintf(cformat, ...) debugPrint(__FILE__, __LINE__, cformat __VA_OPT__(,) __VA_ARGS__)

En utilisant la cformatchaîne de caractères comme argument variadique, on peut contourner les incompatibilités mentionnées précédemment. C'est complexe, mais portable.

#define dbgprintf(...) debugPrint(__FILE__, __LINE__, __VA_ARGS__)

dbgprintf ( "Bonjour, monde" );

qui s'étend à

debugPrint ( __FILE__ , __LINE__ , "Bonjour, monde" );

Un autre exemple est :

dbgprintf ( "%d + %d = %d" , 2 , 2 , 5 );

qui s'étend à

debugPrint ( __FILE__ , __LINE__ , "%d + %d = %d" , 2 , 2 , 5 );

Sans macros variadiques, printfil n'est pas possible d'écrire directement des fonctions d'encapsulation. La solution standard consiste à utiliser la fonctionnalité stdargs du C/C++ et à faire en sorte que la fonction soit appelée vprintf.

Virgule finale

Il existe un problème de portabilité lié à la génération d'une virgule finale avec des arguments vides pour les macros variadiques en C99 . Certains compilateurs (par exemple, Visual Studio lorsqu'il n'utilise pas le nouveau préprocesseur conforme à la norme ) suppriment silencieusement cette virgule finale. D'autres compilateurs (par exemple, GCC ) permettent de l'ajouter ##devant le point __VA_ARGS__.

#define MYLOG(FormatLiteral, ...) fprintf(stderr, "%s(%u): " FormatLiteral " ", __FILE__, __LINE__, __VA_ARGS__)

L'application suivante fonctionne

MYLOG ( "Trop de ballons %u" , 42 );

qui s'étend à

fprintf ( stderr , "%s(%u): " "Trop de ballons %u" " " , __FILE__ , __LINE__ , 42 );

ce qui équivaut à

fprintf ( stderr , "%s(%u): Trop de ballons %u " , __FILE__ , __LINE__ , 42 );

Mais regardez cette application :

MYLOG ( "Attention !" );

qui s'étend à

fprintf ( stderr , "%s(%u): " "Attention !" " " , __FILE__ , __LINE__ , );

ce qui génère une erreur de syntaxe avec GCC.

GCC prend en charge l'extension suivante (non portable) :

#define MYLOG(FormatLiteral, ...) fprintf(stderr, "%s(%u): " FormatLiteral " ", __FILE__, __LINE__, ##__VA_ARGS__)

qui supprime la virgule finale lorsque __VA_ARGS__la valeur est vide.

C23 résout ce problème en introduisant une approche __VA_OPT__similaire à celle de C++.

Alternatives

Avant l'existence des arguments variables en C99, il était assez courant d'utiliser des parenthèses doublement imbriquées pour exploiter le nombre variable d'arguments pouvant être fournis à la printf()fonction :

#define dbgprintf(x) debugPrint x

dbgprintf (( "Bonjour, monde %d" , 27 ));

ce qui se développe en :

debugPrint ( "Bonjour, monde %d" , 27 );

Rouiller

...),*$(),*+

Voici un exemple d'implémentation d'une macro variadique, équivalent àvec! :

// Définir une macro nommée "make_vec!" macro_rules! make_vec { // Correspond à toute expression Rust // et répète le motif séparé par des virgules, zéro ou plusieurs fois ( $( $x : expr ), * ) => { { // Vec doit être entièrement qualifié // pour éviter d'être résolu en un Vec défini par l'utilisateur let mut temp = :: std :: vec :: Vec :: new (); // Effectuer un push vers temp une fois par argument $( temp . push ( $x ); ) * // Retourner temp depuis la macro temp } }; }

Plus d articles de Worldlex Wiki

Revenez a l index pour explorer davantage de pages sur l histoire, la science, la culture, la geographie et la societe en francais.

Explorer l index