Geschichte des Themas
Parameterisierte Makros sind ein wichtiger Teil des C-Präprozessors, entstanden für die schnelle Einführung wiederkehrender Codefragmente und zur Vereinfachung der Fehlersuche. Sie werden für kleine Funktionen, Inlining oder Optimierung verwendet.
Problem
Makros überprüfen die Typen nicht und führen keine vollständige Substitution außer einfacher textueller Ersetzung durch. Fehler treten aufgrund fehlender Klammern und der Ersetzung von Ausdrücken mit Nebenwirkungen auf.
Lösung
Klammern um Parameter und Makrodefinitionen vorsehen, Nebenwirkungen in Argumenten vermeiden und Inline-Funktionen für komplexere Fälle verwenden.
Beispielcode:
#define MAX(a, b) ((a) > (b) ? (a) : (b)) int x = 5, y = 10; int z = MAX(x++, y++); // Gefährlicher Aufruf!
Wichtige Merkmale:
Ersetzt das Makro den Code immer vollständig wie eine Funktion?
Nein! Das Makro ist nur eine textuelle Ersetzung vor der Kompilierung, es kann sich anders verhalten als eine Funktion, wenn die Argumente Ausdrücke mit Nebenwirkungen sind.
Kann jeder Aufruf (einschließlich ++, --) als Makroparameter verwendet werden?
Das ist äußerst gefährlich. Nebenwirkungen treten mehrmals auf, wenn der Parameter im Makro mehr als einmal vorkommt.
Beispielcode:
// Dieser Aufruf erhöht x oder y mehr als um 1 MAX(x++, y++)
Wie sollten Klammern korrekt in Makrodefinitionen verwendet werden?
Sowohl Parameter als auch den Ausdruck innerhalb des Makros in Klammern setzen, um Fehler bei der Assoziativität zu vermeiden, wenn sie innerhalb anderer Ausdrücke aufgerufen werden.
In einem Unternehmen wurde über Jahre hinweg das Makro #define SQUARE(x) xx definiert, und es wurde für Ausdrücke wie SQUARE(a+1) verwendet. Es traten unerwartete Fehler auf: Der Ausdruck entfaltete sich zu a+1a+1, was sich von (a+1)*(a+1) unterscheidet.
Vorteile:
Das Makro SQUARE wurde mit vollständigen Klammern geschrieben: #define SQUARE(x) ((x)*(x)). Seine Verwendung ist standardisiert und dokumentiert.
Vorteile: