Macro vs fonction en C

J’ai toujours vu des exemples et des cas où l’utilisation d’une macro est préférable à l’utilisation de la fonction.

Quelqu’un pourrait-il m’expliquer avec un exemple l’inconvénient d’une macro par rapport à une fonction?

Les macros sont sujettes aux erreurs car elles reposent sur une substitution textuelle et ne font pas de vérification de type. Par exemple, cette macro:

#define square(a) a*a 

fonctionne bien avec un nombre entier:

 square(5) --> 5*5 --> 25 

mais fait des choses très étranges lorsqu’il est utilisé avec des expressions:

 square(1+2) --> 1+2*1+2 --> 1+2+2 --> 5 square(x++) --> x++*x++ --> increments x twice 

Mettre des parenthèses autour des arguments aide mais n’élimine pas complètement ces problèmes.

Lorsque les macros contiennent plusieurs instructions, vous pouvez avoir des problèmes avec les structures de contrôle-stream:

 #define swap(x,y) t=x; x=y; y=t; if(x if(x if(x 

La stratégie habituelle pour corriger cela est de placer les instructions dans une boucle "do {...} while (0)".

Si vous avez deux structures qui contiennent un champ avec le même nom mais une sémantique différente, la même macro peut fonctionner sur les deux, avec des résultats étranges:

 struct shirt { int numButtons; }; struct webpage { int numButtons; }; #define num_button_holes(shirt) ((shirt).numButtons * 4) struct webpage page; page.numButtons = 2; num_button_holes(page) -> 8 

Enfin, les macros peuvent être difficiles à déboguer, produisant des erreurs de syntaxe étranges ou des erreurs d'exécution que vous devez développer pour comprendre (par exemple avec gcc -E), car les débogueurs ne peuvent pas parcourir les macros, comme dans cet exemple:

 #define print(x, y) printf(xy) /* accidentally forgot comma */ print("foo %s", "bar") /* prints "foo %sbar" */ 

Les fonctions et les constantes inline permettent d'éviter beaucoup de ces problèmes avec les macros, mais ne sont pas toujours applicables. Lorsque des macros sont délibérément utilisées pour spécifier un comportement polymorphe, le polymorphism involontaire peut être difficile à éviter. C ++ possède un certain nombre de fonctionnalités telles que des modèles pour aider à créer des constructions polymorphes complexes de manière sécurisée sans utiliser de macros; voir le langage de programmation C ++ de Stroustrup pour plus de détails.

Les effets secondaires sont importants. Voici un cas typique:

 #define min(a,b) (a < b ? a : b) min(x++,y) 

se développe pour:

 (x++ < y ? x++ : y) 

x s'incrémente deux fois dans la même instruction. (et comportement indéfini)


L'écriture de macros multi-lignes est également un problème:

 #define foo(a,b,c) \ a += 10; \ b += 10; \ c += 10; 

Ils nécessitent un \ à la fin de chaque ligne.


Les macros ne peuvent rien "retourner" à moins d'en faire une expression unique:

 int foo(int *a, int *b){ side_effect0(); side_effect1(); return a[0] + b[0]; } 

Impossible de faire cela dans une macro, sauf si vous utilisez l'instruction d'expression de GCC. (EDIT: Vous pouvez utiliser un opérateur de virgule bien que… a négligé cela… Mais il pourrait encore être moins lisible.)


Ordre des opérations: (gracieuseté de @ouah)

 #define min(a,b) (a < b ? a : b) min(x & 0xFF, 42) 

se développe pour:

 (x & 0xFF < 42 ? x & 0xFF : 42) 

Mais & a la préséance inférieure à < . Donc, 0xFF < 42 est évalué en premier.

Caractéristiques de la macro :

  • La macro est prétraitée
  • Aucun type de vérification
  • La longueur du code augmente
  • L’utilisation de macro peut entraîner des effets secondaires
  • La vitesse d’exécution est plus rapide
  • Avant le nom de la macro de compilation est remplacé par la valeur de la macro
  • Utile lorsque le petit code apparaît plusieurs fois
  • La macro ne vérifie pas les erreurs de compilation

Caractéristiques de la fonction :

  • La fonction est compilée
  • La vérification de type est terminée
  • La longueur du code rest la même
  • Aucun effet secondaire
  • La vitesse d’exécution est plus lente
  • Pendant l’appel de fonction, le transfert de contrôle a lieu
  • Utile quand un grand code apparaît plusieurs fois
  • Vérifications de la fonction Comstackr les erreurs