Un outil à employer avec prudence

Les macros sont la source de nombreuses erreurs très difficiles à repérer, puisqu’on ne dispose pas de la version étendue du code. Par exemple, on peut se demander pourquoi dans la macro CARRE ci-dessus nous avons placé ces parenthèses. Mais si l’on écrit :

#define CARRE(x) x * x// ...j = CARRE(i+1);

la dernière ligne deviendra :

j = i+1 * i+1;

qui est interprété comme i + (1*i) +1, soit 2*i+1.

Même avec une définition correcte de CARRE, on peut avoir des surprises :

#define CARRE(x) (x)*(x)// ...int i = 3, j = CARRE(i++);

en sortie i vaut 5, et non 4, parce que la macro a été étendue sous la forme (i++)*(i++) et provoque deux incrémentations. Ce genre d’erreur est particulièrement ardu à repérer.

D’une façon générale les macros sont dangereuses, car il n’y a aucun contrôle des types ; ainsi, si l’on utilise la macro AFFICHE définie ci-avant avec un paramètre non entier, on risque de sérieux problèmes.

En C++, les macros qui définissent des constantes diverses seront avantageusement remplacées par des déclarations de constantes :

const Pi = 3.141592;const Errmsg = "Une erreur s'est produite.\n";

Les macros qui définissent de courtes actions, avec ou sans paramètres, seront remplacées par des fonctions en ligne :

inline long carre(long l) { return l*l;  }inline double carre(double d) { return d*d; }

qui ne posent pas de problèmes, même avec des effets de bord, et qui vérifient les types de leurs paramètres.

Certaines fonctions en ligne sont d’ailleurs bien plus simples que les macros correspondantes. Essayez d’écrire la macro correspondant à :

inline void echange(int& i, int&  j){    int k = i; i = j; j = k; }				inline void echange(long& i, long& j){    long k = i; i = j; j = k; }				inline void echange(double& i, double& j){    double k = i; i = j; j = k; }

Inversement, certaines macros ne peuvent pas être évitées. C’est le cas par exemple de AFFICHE dans la section précédente, qui utilise le nom des variables. On peut toutefois la rendre plus sûre en utilisant les flots de sortie :

#define AFFICHE(x) cout << "Valeur  de " #x " = " << ;;

qui peut alors fonctionner quel que soit le type de x.

Les classes génériques fournissent un autre exemple d’utilisation pratique des macros en C++.

Précédent Précédent Sommaire Sommaire Suivant Suivant