Notre équipe d'experts, après plusieurs jours de recherche et de collecte d'informations, a obtenu les données nécessaires, nous espérons qu'elles vous seront utiles dans votre projet.
Le préprocesseur prend en charge le remplacement des macros de texte. Le remplacement de macro texte de type fonction est également pris en charge.
Syntaxe
#define identificateurliste de remplacement(facultatif) |
(1) | |
#define identifiant( paramètres) liste de remplacement(facultatif) |
(2) | |
#define identifiant( paramètres, ... ) liste de remplacement(facultatif) |
(3) | (depuis C++11) |
#define identifiant( ... ) liste de remplacement(facultatif) |
(4) | (depuis C++11) |
#undef identifiant |
(5) |
Explication
#define
directives
Le site #define
définissent les identifiant comme une macro, c'est-à-dire qu'elles demandent au compilateur de remplacer toutes les occurrences successives de identificateur par liste de remplacement qui peut éventuellement être traité de manière complémentaire. Si l'identificateur est déjà défini comme un type de macro quelconque, le programme est mal formé à moins que les définitions soient identiques.
Macros de type objet
Les macros de type objet remplacent chaque occurrence de defined identificateur par liste de remplacement. Version (1) de la #define
se comporte exactement de la même manière.
Macros de type fonction
Les macros de type fonction remplacent chaque occurrence de défini identificateur par liste de remplacement en prenant en plus un certain nombre d'arguments, qui remplacent alors les occurrences correspondantes de n'importe lequel des éléments paramètres dans les liste de remplacement.
La syntaxe d'une invocation de macro de type fonction est similaire à celle d'un appel de fonction : chaque instance du nom de la macro suivie d'un (
en tant que jeton de prétraitement suivant, introduit la séquence de jetons qui est remplacée par la fonction liste de remplacement. La séquence est terminée par l'élément correspondant )
correspondant, en sautant les paires de parenthèses gauche et droite correspondantes.
Pour la version (2), le nombre d'arguments doit être le même que le nombre de paramètres dans la définition de la macro. Pour les versions (3,4), le nombre d'arguments doit être le suivant supérieur à(jusqu'à C++20)au moins autant que(depuis C++20) le nombre de paramètres (sans compter ...
). Dans le cas contraire, le programme est mal formé. Si l'identificateur n'est pas en notation fonctionnelle, c'est-à-dire qu'il n'a pas de parenthèses après lui-même, il n'est pas remplacé du tout.
Version (2) de la #define
définit une macro simple de type fonction.
La version (3) de la directive #define
définit une macro de type fonction avec un nombre variable d'arguments. Les arguments supplémentaires (appelés arguments variables) sont accessibles en utilisant __VA_ARGS__
identifiant, qui est alors remplacé par des arguments, fournis avec l'identifiant à remplacer.
Version (4) de la #define
définit une macro de type fonction avec un nombre variable d'arguments, mais sans arguments réguliers. Les arguments (appelés arguments variables) ne sont accessibles qu'avec __VA_ARGS__
identifiant, qui est alors remplacé par des arguments, fournis avec l'identifiant à remplacer.
Pour les versions (3,4), replacement-list peut contenir la séquence de jetons #defineF(...)f(0__VA_OPT__(,) __VA_ARGS__)#defineG(X,...)f(0, X __VA_OPT__(,) __VA_ARGS__)#defineSDEF(sname,...) S sname __VA_OPT__(={ __VA_ARGS__ })F(a, b, c)// replaced by f(0, a, b, c)F()// replaced by f(0)G(a, b, c)// replaced by f(0, a, b, c)G(a,)// replaced by f(0, a)G(a)// replaced by f(0, a)SDEF(foo);// replaced by S foo;SDEF(bar,1,2);// replaced by S bar = { 1, 2 }; |
(depuis C++20) |
Remarque : si un argument d'une macro de type fonction comprend des virgules qui ne sont pas protégées par des paires appariées de parenthèses gauche et droite (ce que l'on trouve le plus souvent dans les listes d'arguments de modèles, comme dans la section assert(std::is_same_v<int, int>);
ou BOOST_FOREACH(std::pair<int,int> p, m)
), la virgule est interprétée comme un séparateur d'argument de macro, ce qui entraîne un échec de compilation dû à une non-concordance du nombre d'arguments.
Noms de macro réservés
Une unité de traduction qui comprend un en-tête de bibliothèque standard ne peut pas #define
ou #undef
noms déclarés dans tout en-tête de bibliothèque standard.
Une unité de traduction qui utilise une partie quelconque de la bibliothèque standard ne peut pas #define
ou #undef
des noms lexicalement identiques à :
- mots-clés
|
(depuis C++11) |
sauf que et |
(depuis C++20) |
Dans le cas contraire, le comportement est indéfini.
#
et ##
opérateurs
Dans les macros de type fonction, un #
devant un identificateur dans le liste de remplacement soumet l'identifiant à un remplacement de paramètres et place le résultat entre guillemets, créant ainsi une chaîne de caractères littérale. En outre, le préprocesseur ajoute des barres obliques inverses pour échapper aux guillemets entourant les chaînes de caractères intégrées, le cas échéant, et double les barres obliques inverses dans la chaîne de caractères si nécessaire. Tous les espaces en tête et en queue de chaîne sont supprimés, et toute séquence d'espaces au milieu du texte (mais pas à l'intérieur des chaînes littérales imbriquées) est réduite à un seul espace. Cette opération est appelée "stringification". Si le résultat de la stringification n'est pas un littéral de chaîne valide, le comportement est indéfini.
Lorsque #defineshowlist(...)puts(#__VA_ARGS__)showlist();// expands to puts("")showlist(1,"x",int);// expands to puts("1, "x", int") |
(depuis C++11) |
A ##
entre deux identificateurs successifs quelconques dans le liste de remplacement exécute le remplacement de paramètres sur les deux identificateurs (qui ne sont pas macro-expansés en premier) et concatène ensuite le résultat. Cette opération est appelée "concaténation" ou "collage de jetons". Seuls les jetons qui forment ensemble un jeton valide peuvent être collés : les identificateurs qui forment un identificateur plus long, les chiffres qui forment un nombre ou les opérateurs. +
et =
qui forment un +=
. Un commentaire ne peut pas être créé en collant /
et *
car les commentaires sont supprimés du texte avant que la substitution de macro soit prise en compte. Si le résultat de la concaténation n'est pas un token valide, le comportement est indéfini.
Note : certains compilateurs proposent une extension qui permet au ## d'apparaître après une virgule et avant __VA_ARGS__, auquel cas le ## ne fait rien lorsque les arguments de la variable sont présents, mais supprime la virgule lorsque les arguments de la variable ne sont pas présents : cela permet de définir des macros telles que... fprintf (stderr, format, ##__VA_ARGS__)
.
#undef
directive
Le site #undef
indéfinit la directive identifiant c'est-à-dire qu'elle annule la définition précédente de l'identificateur identificateur par #define
directive. Si l'identifiant n'a pas de macro associée, la directive est ignorée.
Macros prédéfinies
Les noms de macro suivants sont prédéfinis dans chaque unité de traduction.
__cplusplus | dénote la version de la norme C++ qui est utilisée, s'étend à la valeur 199711L.(jusqu'à C++11), 201103L (C++11), 201402L (C++14) ou 201703L (C++17) (constante macro) |
__STDC_HOSTED__(C++11) | s'étend à la constante entière 1 si l'implémentation est hébergée (fonctionne sous un OS), 0 si elle est autonome (fonctionne sans système d'exploitation). (constante macro) |
__FILE__ | se développe vers le nom du fichier actuel, comme un littéral de chaîne de caractères, peut être modifié par la directive #line. (constante macro) |
__LINE__ | se développe vers le numéro de ligne du fichier source, une constante entière, peut être modifiée par la directive #line. (constante macro) |
__DATE__ | étend à la date de la traduction, une chaîne de caractères littérale de la forme "Mmm dd yyyy". Le premier caractère de "dd" est un espace si le jour du mois est inférieur à 10. Le nom du mois est comme s'il était généré par std::asctime() (constante macro) |
__TIME__ | étend à l'heure de la traduction, un littéral de chaîne de caractères de la forme "hh:mm:ss". (constante macro) |
__STDCPP_DEFAULT_NEW_ALIGNMENT__(C++17) | s'étend à un std::size_t dont la valeur est l'alignement garanti par un appel à l'opérateur new non conscient de l'alignement (des alignements plus importants seront transmis à la surcharge consciente de l'alignement, telle que operator new(std::size_t, std::align_val_t) (constante macro) |
Les noms de macro supplémentaires suivants peuvent être prédéfinis par les implémentations.
__STDC__ | valeur définie par l'implémentation, si elle est présente, généralement utilisée pour indiquer la conformité au langage C. (constante macro) |
__STDC_VERSION__(C++11) | valeur définie par l'implémentation, si présente (constante macro) |
__STDC_ISO_10646__(C++11) | se développe en une constante entière de la forme yyyymmL , si wchar_t utilise Unicode, la date indique la dernière révision d'Unicode prise en charge. (constante macro) |
__STDC_MB_MIGHT_NEQ_WC__(C++11) | s'étend à 1 si 'x' == L'x' pourrait être faux pour un membre du jeu de caractères de base, comme sur les systèmes basés sur EBCDIC qui utilisent Unicode pour wchar_t. (constante macro) |
__STDCPP_STRICT_POINTER_SAFETY__(C++11) | s'étend à 1 si l'implémentation est stricte std::pointer_safety (constante macro) |
__STDCPP_THREADS__(C++11) | s'étend à 1 si le programme peut avoir plus d'un fil d'exécution (constante macro) |
Les valeurs de ces macros (sauf pour __FILE__
et __LINE__
) restent constantes tout au long de l'unité de traduction. Les tentatives de redéfinition ou d'indéfinition de ces macros entraînent un comportement non défini.
Note : dans la portée de chaque corps de fonction, il existe une variable prédéfinie spéciale locale à la fonction nommée. __func__
(depuis C++11) définie comme un tableau de caractères statique contenant le nom de la fonction dans un format défini par l'implémentation. Il ne s'agit pas d'une macro de préprocesseur, mais elle est utilisée avec la variable __FILE__
et __LINE__
par exemple par assert
.
Macros de test des caractéristiques de la langueLes macros suivantes sont prédéfinies dans chaque unité de traduction.
|
(depuis C++20) |
Exemple
#include// Make function factory and use it#defineFUNCTION(name, a)int fun_##name(){return a;}FUNCTION(abcd,12)FUNCTION(fff,2)FUNCTION(qqq,23)#undefFUNCTION#defineFUNCTION34#defineOUTPUT(a) std::cout <<"output: "#a<<'n'// Using a macro in the definition of a later macro#defineWORD"Hello "#defineOUTER(...) WORD #__VA_ARGS__intmain(){ std::cout <<"abcd: "<<fun_abcd()<<'n'; std::cout <<"fff: "<<fun_fff()<<'n'; std::cout <<"qqq: "<<fun_qqq()<<'n'; std::cout << FUNCTION <<'n';OUTPUT(million);//note the lack of quotes std::cout <<OUTER(World)<<'n'; std::cout <<OUTER(WORD World)<<'n';}
Sortie :
abcd:12 fff:2 qqq:2334 output: million Hello World Hello WORD World
Voir aussi