web-dev-qa-db-fra.com

Qu'est-ce qu'une macro? Différence entre macro et fonction?

Je ne comprends pas bien le concept macro. Qu'est-ce qu'une macro? Je ne comprends pas en quoi est-ce différent de la fonction? La fonction et la macro contiennent un bloc de code. Alors, comment la macro et la fonction diffèrent-elles?

16
Edoardo Sorgentone

Remarque

Je voudrais ajouter la clarification suivante après avoir observé le schéma de vote polarisant sur cette réponse.

La réponse n'a pas été écrite en gardant à l'esprit l'exactitude technique et une large généralisation. C'était une humble tentative d'expliquer dans un langage simple, la différence entre les macros et les fonctions à un débutant en programmation, sans chercher à être complet ou précis (en fait c'est loin d'être précis). Le langage de programmation C était dans mon esprit lors de la rédaction de la réponse, mais je m'excuse de ne pas l'avoir mentionné clairement et d'avoir causé une confusion (potentielle).

Je considère vraiment le réponse partagée par Jörg W Mittag . C'était perspicace de le lire (à quel point je le sais moins) et je l'ai voté peu de temps après sa publication. Je viens de commencer sur Software Engineering Stack Exchange, et l'expérience et les discussions jusqu'à présent ont été vraiment pertinentes.

Je laisserai cette réponse ici car elle peut être utile pour d'autres débutants en développement de logiciels, essayant de comprendre un concept sans s'enliser dans les précisions techniques.


La macro et la fonction représentent une unité de code autonome. Ils sont tous deux des outils qui aident à la conception modulaire d'un programme. Du point de vue du programmeur qui écrit le code source, ils semblent assez similaires. Cependant, ils diffèrent dans la façon dont ils sont traités pendant le cycle de vie d'exécution du programme.

Une macro est définie une fois et utilisée à de nombreux endroits dans un programme. La macro est développée en ligne pendant la phase de prétraitement. Ainsi, techniquement, il ne reste pas une entité distincte une fois le code source compilé. Les instructions de la définition de macro font partie des instructions du programme, tout comme les autres instructions.

Le motif derrière l'écriture d'une macro est de faciliter l'écriture et la gestion du code source pour le programmeur. Les macros sont généralement souhaitées pour des tâches plus simples où l'écriture d'une fonction à part entière serait une pénalité de surcharge/d'exécution. Voici des exemples de situations où une macro est préférable à une fonction:

  • Utilisation de valeurs constantes (telles que des valeurs mathématiques ou scientifiques) ou d'un paramètre spécifique au programme.

  • Impression des messages de journal ou gestion des assertions.

  • Effectuer des calculs simples ou des vérifications de conditions.

Lorsque vous utilisez une macro, il est facile de faire des changements/corrections en un seul endroit qui sont instantanément disponibles partout où la macro est utilisée dans le programme. Une simple recompilation du programme est nécessaire pour que les modifications prennent effet.

Le code de fonction, d'autre part, est compilé en tant qu'unité distincte dans le programme et n'est chargé dans la mémoire pendant l'exécution du programme que si cela est nécessaire. Le code de fonction conserve son identité indépendante du reste du programme. Le code chargé est réutilisé si la fonction est appelée plusieurs fois. Lorsque l'appel de fonction est rencontré dans le programme en cours d'exécution, le contrôle lui est transmis par le sous-système d'exécution et le contexte du programme en cours d'exécution (adresse d'instruction de retour) est conservé.

Cependant, il y a une légère pénalité de performance qui doit être rencontrée lors de l'appel d'une fonction (changement de contexte, préservation de l'adresse de retour des instructions du programme principal, passage de paramètres et gestion des valeurs de retour, etc.). Par conséquent, l'utilisation de la fonction n'est souhaitée que pour des blocs de code complexes (contre des macros qui traitent des cas plus simples).

Avec l'expérience, un programmeur prend une décision judicieuse quant à savoir si un morceau de code sera un bon ajustement en tant que macro ou fonction dans l'architecture globale du programme.

7
Nimesh Neema

Malheureusement, il existe plusieurs utilisations différentes du terme "macro" dans la programmation.

Dans la famille de langages LISP, et les langages inspirés par ceux-ci, ainsi que de nombreux langages modernes fonctionnels ou inspirés des fonctionnalités comme Scala et Haskell, ainsi que certains langages impératifs comme Boo, une macro est un morceau de code qui s'exécute au moment de la compilation (ou au moins avant l'exécution pour les implémentations sans compilateur) et peut transformer l'arborescence de syntaxe abstraite (ou quel que soit l'équivalent dans le langage particulier, par exemple dans LISP, ce serait les S-Expressions) dans quelque chose d'autre pendant la compilation. Par exemple, dans de nombreuses implémentations de Scheme, for est une macro qui se développe en plusieurs appels au corps. Dans les langages de type statique, les macros sont souvent de type -safe, c'est-à-dire qu'ils ne peuvent pas produire de code mal typé.

Dans la famille C des langues, les macros ressemblent davantage à une substitution textuelle. Ce qui signifie également qu'ils peuvent produire du code qui n'est pas bien typé, ni même syntaxiquement légal.

Dans les macro-assembleurs, les "macros" font référence à des "instructions virtuelles", c'est-à-dire des instructions que le CPU ne prend pas en charge de manière native mais qui sont utiles, et donc l'assembleur vous permet d'utiliser ces instructions et les étendra en plusieurs instructions que le CPU comprend .

Dans le script d'application, une "macro" fait référence à une série d'actions que l'utilisateur peut "enregistrer" et "lire".

Tous ces éléments sont en quelque sorte des types de code exécutable, ce qui signifie qu'ils peuvent dans un certain sens être considérés comme des fonctions. Cependant, dans le cas des macros LISP, par exemple, leurs entrées et sorties sont des fragments de programme. Dans le cas de C, leurs entrées et sorties sont des jetons. Les trois premiers ont également la distinction très importante qu'ils sont exécutés au moment de la compilation. En fait, les macros du préprocesseur C, comme son nom l'indique, sont en fait exécutées avant même que le code n'atteigne le compilateur.

65
Jörg W Mittag

Dans la famille de langage C, une définition de macro, une commande de préprocesseur, spécifie un modèle de code paramétré qui est substitué à appel de macro sans être compilé à la définition. Cela signifie que toutes les variables libres doivent être liées dans le contexte de l'appel de macro. Arguments de paramètre avec un effet secondaire comme i++ pourrait être répété en utilisant plusieurs fois le paramètre. La substitution textuelle de l'argument 1 + 2 d'un paramètre x se produit avant la compilation et peut provoquer un comportement inattendu x * 3 (7 i.o. 9). Une erreur dans le corps de macro de la définition de macro apparaîtra uniquement lors de la compilation lors de l'appel de macro.

définition de fonction spécifie le code avec des variables libres liées au contexte du corps de la fonction; pas le appel de fonction.

La macro, cependant apparemment négative, donne accès à l'appel, au numéro de ligne et au fichier source, à l'argument sous la forme d'une chaîne .

2
Joop Eggen

En termes légèrement plus abstraits, une macro est à la syntaxe comme une fonction aux données. Une fonction (dans l'abstrait) encapsule une transformation sur les données. Il prend ses arguments en tant que données évaluées, effectue certaines opérations sur ces derniers et renvoie un résultat qui n'est également que des données.

Une macro en revanche prend un peu syntaxe non évalué et opère sur cela. Pour les langages de type C, la syntaxe entre au niveau du jeton. Pour les langages avec des macros de type LISP, ils obtiennent la syntaxe représentée comme un AST. La macro doit renvoyer un nouveau morceau de syntaxe.

2
Ashton Wiersdorf

Une macro fait généralement référence à quelque chose qui est développé en place , remplaçant le macro "appel" pendant la compilation ou le prétraitement avec des instructions individuelles dans la langue cible. Au moment de l'exécution, il n'y aura généralement aucune indication sur le début et la fin de la macro.

Ceci est distinct d'un sous-programme , qui est un morceau de code réutilisable qui est situé séparément en mémoire, auquel le contrôle est passé à l'exécution . Les "fonctions", "procédures" et "méthodes" dans la plupart des langages de programmation entrent dans cette catégorie.

Comme réponse de Jörg W Mittag discute, les détails exacts varient selon les langues: dans certains, comme C, une macro effectue une substitution de texte dans le code source; dans certains, comme LISP, il effectue la manipulation d'une forme intermédiaire comme un arbre de syntaxe abstraite. Il y a aussi quelques zones grises: certains langages ont une notation pour les "fonctions en ligne", qui sont définies comme une fonction, mais développées dans le programme compilé comme une macro.

La plupart des langages encouragent les programmeurs à raisonner sur chaque sous-programme de manière isolée, à définir des contrats de type pour les entrées et les sorties et à masquer d'autres informations sur le code appelant. Il y a souvent un impact sur les performances à appeler un sous-programme que les macros n'encourent pas, et les macros peuvent être capables de manipuler le programme d'une manière qu'un sous-programme ne peut pas. Les macros peuvent donc être considérées comme "de niveau inférieur" que les sous-programmes, car elles fonctionnent sur une base moins abstraite.

0
IMSoP

La macro est exécutée pendant la compilation et la fonction est exécutée au moment de l'exécution.

Exemple:

#include <stdio.h>

#define macro_sum(x,y) (x+y)

int func_sum(x,y) {
    return x+y;
}

int main(void) {
    printf("%d\n", macro_sum(2,3));
    printf("%d\n", func_sum(2,3));
    return 0;
}

Ainsi, lors de la compilation, le code est changé en:

#include <stdio.h>

int func_sum(x,y) {
    return x+y;
}

int main(void) {
    printf("%d\n", (2+3));
    printf("%d\n", func_sum(2,3));
    return 0;
}
0
david72