it-swarm.com.de

Was ist ein Makro? Unterschied zwischen Makro und Funktion?

Ich verstehe das Makrokonzept nicht gut. Was ist ein Makro? Ich verstehe nicht, wie es sich von der Funktion unterscheidet? Sowohl Funktion als auch Makro enthalten einen Codeblock. Wie unterscheiden sich Makro und Funktion?

16

Hinweis

Ich möchte die folgende Klarstellung hinzufügen, nachdem ich das polarisierende Abstimmungsmuster zu dieser Antwort beobachtet habe.

Die Antwort wurde nicht unter Berücksichtigung der technischen Genauigkeit und der allgemeinen Verallgemeinerung geschrieben. Es war ein bescheidener Versuch, einem Programmier-Neuling den Unterschied zwischen Makros und Funktionen in einfacher Sprache zu erklären, ohne zu versuchen, vollständig oder genau zu sein (tatsächlich ist es alles andere als genau). Bei der Ausarbeitung der Antwort dachte ich an die Programmiersprache C, aber ich entschuldige mich dafür, dass ich sie nicht klar erwähnt habe und (potenzielle) Verwirrung stiftete.

Ich betrachte das Antwort von Jörg W Mittag . Es war aufschlussreich, es zu lesen (wie wenig ich weiß) und ich habe es kurz nach der Veröffentlichung positiv bewertet. Ich habe gerade mit Software Engineering Stack Exchange angefangen und die bisherigen Erfahrungen und Diskussionen waren wirklich aufschlussreich.

Ich werde diese Antwort hier belassen, da sie für andere Softwareentwickler hilfreich sein kann, die versuchen, ein Konzept zu verstehen, ohne sich auf technische Genauigkeit zu beschränken.


Sowohl das Makro als auch die Funktion repräsentieren eine in sich geschlossene Codeeinheit. Beide sind Werkzeuge, die beim modularen Aufbau eines Programms helfen. Aus der Sicht des Programmierers, der den Quellcode schreibt, sehen sie ziemlich ähnlich aus. Sie unterscheiden sich jedoch darin, wie sie während des Programmausführungslebenszyklus behandelt werden.

Ein Makro wird einmal definiert und an vielen Stellen in einem Programm verwendet. Das Makro wird während der Vorverarbeitungsphase inline erweitert. Somit bleibt es technisch gesehen keine separate Entität, sobald der Quellcode kompiliert wurde. Die Anweisungen in der Makrodefinition werden wie andere Anweisungen Teil der Programmanweisungen.

Das Motiv beim Schreiben eines Makros besteht darin, dem Programmierer das Schreiben und Verwalten von Quellcode zu erleichtern. Makros sind im Allgemeinen für einfachere Aufgaben erwünscht, bei denen das Schreiben einer vollwertigen Funktion einen Leistungsaufwand/eine Laufzeitstrafe bedeuten würde. Beispiele für Situationen, in denen ein Makro der Funktion vorzuziehen ist, sind:

  • Verwenden Sie konstante Werte (z. B. mathematische oder wissenschaftliche Werte) oder programmspezifische Parameter.

  • Drucken von Protokollnachrichten oder Behandeln von Zusicherungen.

  • Durchführen einfacher Berechnungen oder Zustandsprüfungen.

Bei Verwendung von Makros ist es einfach, Änderungen/Korrekturen an einem Ort vorzunehmen, die sofort überall dort verfügbar sind, wo das Makro im Programm verwendet wird. Eine einfache Neukompilierung des Programms ist erforderlich, damit die Änderungen wirksam werden.

Funktionscode hingegen wird als separate Einheit innerhalb des Programms kompiliert und während der Programmausführung nur dann in den Speicher geladen, wenn dies erforderlich ist. Der Funktionscode behält seine vom Rest des Programms unabhängige Identität. Der geladene Code wird wiederverwendet, wenn die Funktion mehrmals aufgerufen wird. Wenn der Funktionsaufruf im laufenden Programm auftritt, wird die Steuerung vom Laufzeitsubsystem an dieses übergeben, und der Kontext des laufenden Programms (Rückgabeanweisungsadresse) bleibt erhalten.

Es gibt jedoch eine leichte Leistungsminderung, die beim Aufrufen einer Funktion auftreten muss (Kontextwechsel, Beibehalten der Rücksprungadresse der Hauptprogrammanweisungen, Übergeben von Parametern und Behandeln von Rückgabewerten usw.). Daher ist die Verwendung von Funktionen nur für komplexe Codeblöcke erwünscht (gegen Makros, die einfachere Fälle behandeln).

Mit der Erfahrung trifft ein Programmierer eine vernünftige Entscheidung, ob ein Code als Makro oder Funktion in die gesamte Programmarchitektur passt.

7
Nimesh Neema

Leider gibt es in der Programmierung mehrere verschiedene Verwendungen des Begriffs "Makro".

In der LISP-Sprachfamilie und den von ihnen inspirierten Sprachen sowie vielen modernen funktionalen oder funktional inspirierten Sprachen wie Scala und Haskell sowie einigen imperativen Sprachen wie Boo) ist ein Makro Ein Teil des Codes, der zur Kompilierungszeit (oder zumindest vor der Laufzeit für Implementierungen ohne Compiler) ausgeführt wird und den abstrakten Syntaxbaum transformieren kann (oder was auch immer das Äquivalent in der jeweiligen Sprache ist, z. B. in LISP). Es wären die S-Ausdrücke), die während der Kompilierung in etwas anderes umgewandelt werden. Beispielsweise ist in vielen Schema-Implementierungen for ein Makro, das sich zu mehreren Aufrufen des Körpers erweitert. In statisch typisierten Sprachen werden häufig Makros eingegeben -sicher, dh sie können keinen Code erzeugen, der nicht gut typisiert ist.

In der C-Sprachfamilie ähneln Makros eher der Textsubstitution. Dies bedeutet auch, dass sie Code erzeugen können, der nicht gut typisiert oder sogar syntaktisch nicht legal ist.

In Makro-Assemblern beziehen sich "Makros" auf "virtuelle Anweisungen", dh Anweisungen, die die CPU nicht nativ unterstützt, die jedoch nützlich sind. Der Assembler ermöglicht Ihnen daher, diese Anweisungen zu verwenden, und erweitert sie zu mehreren Anweisungen, die die CPU versteht .

In Anwendungsskripten bezieht sich ein "Makro" auf eine Reihe von Aktionen, die der Benutzer "aufzeichnen" und "wiedergeben" kann.

All dies sind in gewisser Weise Arten von ausführbarem Code, was bedeutet, dass sie in gewissem Sinne als Funktionen angesehen werden können. Bei LISP-Makros sind ihre Eingabe und Ausgabe jedoch beispielsweise Programmfragmente. Im Fall von C sind ihre Ein- und Ausgabe Token. Die ersten drei haben auch den sehr wichtigen Unterschied, dass sie ausgeführt werden zur Kompilierungszeit. Tatsächlich werden C-Präprozessor-Makros, wie der Name schon sagt, tatsächlich ausgeführt bevor der Code überhaupt den Compiler erreicht.

65
Jörg W Mittag

In der C-Sprachfamilie gibt ein Makrodefinition, ein Präprozessorbefehl, eine parametrisierte Codevorlage an, die beim Makroaufruf ersetzt wird, ohne bei der Definition kompiliert zu werden. Dies bedeutet, dass alle freien Variablen im Kontext des Makroaufrufs gebunden werden sollten. Parameterargumente mit einem Nebeneffekt wie i++ könnte durch mehrmalige Verwendung des Parameters wiederholt werden. Die textuelle Ersetzung des Arguments 1 + 2 eines Parameters x tritt vor der Kompilierung auf und kann zu unerwartetem Verhalten führen x * 3 (7 i.o. 9). Ein Fehler im Makrokörper der Makrodefinition wird nur beim Kompilieren beim Makroaufruf angezeigt.

Das Funktionsdefinition gibt Code mit freien Variablen an, die an den Kontext des Funktionskörpers gebunden sind. nicht das Funktionsaufruf.

Das Makro, das jedoch scheinbar negativ ist, bietet Zugriff auf den Aufruf, die Zeilennummer und die Quelldatei, das Argument als Zeichenfolge .

2
Joop Eggen

In etwas abstrakteren Begriffen ist ein Makro die Syntax wie eine Funktion die Daten. Eine Funktion (in der Zusammenfassung) kapselt eine Transformation von Daten. Es nimmt seine Argumente als ausgewertete Daten, führt einige Operationen an ihnen aus und gibt ein Ergebnis zurück, das ebenfalls nur Daten sind.

Ein Makro nimmt dagegen etwas unbewertetes Syntax und arbeitet damit. Bei C-ähnlichen Sprachen erfolgt die Syntax auf Token-Ebene. Für Sprachen mit LISP-ähnlichen Makros wird die Syntax als AST dargestellt. Das Makro muss einen neuen Syntaxblock zurückgeben.

2

Ein Makro bezieht sich im Allgemeinen auf etwas, das an Ort und Stelle erweitert ist und das ersetzt Makro "Aufruf" während der Kompilierung oder Vorverarbeitung mit individuellen Anweisungen in der Zielsprache. Zur Laufzeit gibt es im Allgemeinen keinen Hinweis darauf, wo das Makro beginnt und endet.

Dies unterscheidet sich von einer Unterroutine , bei der es sich um einen wiederverwendbaren Code handelt, der sich separat im Speicher befindet und zu dem Die Steuerung wird zur Laufzeit übergeben . Die "Funktionen", "Prozeduren" und "Methoden" in den meisten Programmiersprachen fallen in diese Kategorie.

Wie Antwort von Jörg W Mittag erläutert, variieren die genauen Details zwischen den Sprachen: In einigen, wie z. B. C, führt ein Makro eine Textersetzung im Quellcode durch; In einigen Fällen, wie z. B. LISP, wird eine Zwischenform wie ein abstrakter Syntaxbaum bearbeitet. Es gibt auch einige Grauzonen: Einige Sprachen haben eine Notation für "Inline-Funktionen", die wie eine Funktion definiert, aber wie ein Makro in das kompilierte Programm erweitert werden.

Die meisten Sprachen ermutigen Programmierer, jede Unterroutine isoliert zu betrachten, Typverträge für Ein- und Ausgaben zu definieren und andere Informationen über den aufrufenden Code auszublenden. Das Aufrufen einer Unterroutine, deren Makros nicht anfallen, wirkt sich häufig auf die Leistung aus, und Makros können das Programm möglicherweise auf eine Weise bearbeiten, die eine Unterroutine nicht kann. Makros können daher als "niedrigere Ebene" als Unterprogramme betrachtet werden, da sie weniger abstrakt arbeiten.

0
IMSoP

Das Makro wird während der Kompilierung ausgeführt und die Funktion wird zur Laufzeit ausgeführt.

Beispiel:

#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;
}

Während der Kompilierung wird der Code also tatsächlich geändert in:

#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