Le préprocesseur peut, lors du mécanisme de remplacement de texte, utiliser des paramètres fournis à l'identificateur à remplacer. Ces paramètres sont alors replacés sans modification dans le texte de remplacement. Le texte de remplacement est alors appelé macro.
La syntaxe des macros est la suivante :
#define macro(paramètre[, paramètre [...]]) définition
Note : Pour poursuivre une définition sur la ligne suivante, terminez la ligne courante par le signe '\'.
Le mécanisme des macros permet de faire l'équivalent de fonctions générales, qui fonctionnent pour tous les types. Ainsi, la macro MAX renvoie le maximum de ses deux paramètres, qu'ils soient entiers, longs ou réels. Cependant, on prendra garde au fait que les paramètres passés à une macro sont évalués par celle-ci à chaque fois qu'ils sont utilisés dans la définition de la macro. Cela peut poser des problèmes de performances ou, pire, provoquer des effets de bords indésirables. Par exemple, l'utilisation suivante de la macro MIN :
provoque le remplacement suivant : soit deux appels de la fonctionf
si f(3) est inférieur à
5, et un seul appel sinon. Si la fonction f
ainsi appelée
modifie des variables globales, le résultat de la macro ne sera certainement pas celui attendu,
puisque le nombre d'appels est variable pour une même expression. On évitera donc, autant que faire
se peut, d'utiliser des expressions ayant des effets de bords en paramètres d'une macro. Les écritures
du type :
sont donc à prohiber.
On mettra toujours des parenthèses autour des paramètres de la macro. En effet, ces paramètres peuvent être des expressions composées, qui doivent être calculées complètement avant d'être utilisées dans la macro. Les parenthèses forcent ce calcul. Si on ne les met pas, les règles de priorités peuvent générer une erreur de logique dans la macro elle-même. De même, on entourera de parenthèses les macros renvoyant une valeur, afin de forcer leur évaluation complète avant toute utilisation dans une autre expression. Par exemple :
est une macro fausse. La ligne :mul(2+3,5+9)sera remplacée par :
2+3*5+9ce qui vaut 26, et non pas 70 comme on l'aurait attendu. La bonne macro est :
#define mul(x,y) ((x)*(y))car elle donne le texte suivant :
((2+3)*(5+9))et le résultat est correct. De même, la macro : est fausse, car l'expression suivante :
add(2,3)*5est remplacée textuellement par :
(2)+(3)*5dont le résultat est 17 et non 25 comme on l'aurait espéré. Cette macro doit donc se déclarer comme suit :
#define add(x,y) ((x)+(y))
Ainsi, les parenthèses assurent un comportement cohérent de la macro. Comme on le voit, les parenthèses peuvent alourdir les définitions des macros, mais elles sont absolument nécessaires.
Le résultat du remplacement d'une macro par sa définition est, lui aussi, soumis au préprocesseur. Par conséquent, une macro peut utiliser une autre macro ou une constante définie avec #define. Cependant, ce mécanisme est limité aux macros qui n'ont pas encore été remplacées afin d'éviter une récursion infinie du préprocesseur. Par exemple :
définit la macro toto. Si plus loin on utilise « toto(3) », le texte de remplacement final sera « toto((3)+1) » et non pas l'expression infinie « (...(((3)+1)+1...)+1 ».Le préprocesseur définit automatiquement la macro defined, qui permet de tester si un identificateur est connu du préprocesseur. Sa syntaxe est la suivante :
defined(identificateur)
La valeur de cette macro est 1 si l'identificateur existe, 0 sinon. Elle est utilisée principalement avec la directive #if. Il est donc équivalent d'écrire :
#if defined(identificateur) ⋮ #endifet :
#ifdef identificateur ⋮ #endif
Cependant, defined permet l'écriture d'expressions plus complexes que la directive #if.
Précédent | Sommaire | Suivant |
Les commandes du préprocesseur | Niveau supérieur | Manipulation de chaînes de caractères dans les macros |