Les macros sont la source de nombreuses erreurs très difficiles à repérer, puisquon 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 lon é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 derreur est particulièrement ardu à repérer.
Dune façon générale les macros sont dangereuses, car il ny a aucun contrôle des types ; ainsi, si lon 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 dailleurs 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. Cest 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 dutilisation pratique des macros en C++.
![]() | ![]() | Suivant ![]() |