Sprachkonzepte Preprozessor Operatoren Kontrollstrukturen Typen OOP Bibliotheken |
#defineMittels der #define-Direktive wird einem Namen ein Makro zugewiesen, welches im gesamten darauf folgenden Code den Namen ersetzt. Makros können Parameter besitzen, die im Code ähnlich wie Funktionen
Siehe auch #undef, #ifdef, #if, defined DetailsMakros sind sehr gut geeignet für allgemeingültige Konstanten wie Pi, e, Wurzel-2, die Erdanziehungskraft g... Solche und ähnliche unveränderbare konstanten Werte sind insofern bevorzugt als Makros zu definieren, da sie nicht wie eine Variable während dem Programmablauf erst aus dem Speicher gelesen werden müssen, sondern direkt im Programmcode compiliert sind. Des weiteren werden Makros oftmals zur bedingten Compilierung verwendet, beispielsweise mit Flags wie Da Makros jedoch nicht unproblematisch sind, wird empfohlen, ein eindeutiges Erkennungsmerkmal für Makros, üblicherweise GROSSSCHREIBUNG, zu verwenden, sowie möglichst kleine, überschaubare Makros zu schreiben. Makros sind sehr anfällig auf Nebeneffekte, weswegen empfohlen wird, Parameter von parametrisierten Makros nicht zu beschreiben (beispielsweise mittels Inkrement oder Dekrement), sowie Berechnungen, Casts und Dereferenzierungen immer mit Klammern zu umschliessen: Parametrisierte Makros können mit den Auslassungspunkten ... auch Parameter variabler Länge besitzen. Ein Makro muss in einer einzelnen Zeile definiert werden. Mehrzeilige Makros können mittels einem Backslash \ am Ende der Zeile erreicht werden. Makros werden erst dann ausgewertet, wenn sie gebraucht werden, jedes Mal von neuem:
Makros können keine weiteren Direktiven enthalten. Sowohl das führende #, als auch der Name der Direktive werden durch den Preprozessor nicht aufgelöst:
Der Fehler, der hierbei entsteht, ist verwirrend. Er entsteht durch den Compiler, nicht durch den Preprozessor. Das obige Beispiel wird in folgende Zeile übersetzt:
Daraufhin jedoch beendet der Preprozessor seinen Dienst und übergibt diesen Code an den eigentlichen Compiler, der mit dem # nichts anfangen kann. Verschluckung des Semikolons ;Da der Preprozessor Zeichen für Zeichen umwandelt, ist es nicht notwendig, ein Makro mit einem Semikolon ; abzuschliessen, wenn man es im eigentlichen Code wie eine Funktion aussehen lassen möchte.
Diese Massnahme ist bekannt unter dem Begriff
Die Verschluckung des Semikolons beschreibt zudem ein weiteres Phänomen, welches mit der Bereichs-Klammerung mit geschweiften Klammern {} und der Benutzung des Makro vor einem else-Statement einer einzeiligen if-Bedingung zu tun hat. Bereichs-Klammerung ging jedoch heutzutags aufgrund der Veränderung des Programmierstils fast gänzlich verloren, weswegen für dieses Phänomen auf weitere Quellen verwiesen wird. NebeneffekteDer Gebrauch von Makros ist nicht bei jedem Programmierer gleich beliebt. Oftmals geht vergessen, dass Makros nicht wie Variablen oder Funktionen ausgelesen oder aufgerufen werden, sondern durch den Preprozessor Zeichen für Zeichen direkt in den Programmcode hineingeschrieben werden. Folgendes Programm verdeutlicht die Problematik:
Während bei der ersten Variante zweimal derselbe Wert ausgegeben wird, erhält man bei der Makro-Variante zwei verschiedene Werte, obschon das Makro und die Funktion denselben Code definieren. Der Unterschied besteht darin, dass bei der ersten Variante zuerst die Funktion
Dies bedeutet, dass Klammerung von BerechnungenFür den Preprozessor oder Compiler gibt es feste Regeln, in welcher Reihenfolge Operanden umgesetzt werden. Der Programmierer kann diese Reihenfolge unter anderem mit Klammerung steuern. Bei Makros wird empfohlen, um Berechnungen herum stets Klammern zu setzen. Folgendes Beispiel zeigt, was passiert, wenn man eine Berechnung nicht korrekt klammert:
Der Preprozessor übersetzt den Code in die folgenden Zeilen:
In der ersten Zeile wird zuerst Klammerung von CastsOftmals werden in Makros explizite Casts gemacht. In den allermeisten Fällen wird man damit keine Probleme haben, allerdings zeigt folgendes Programm ein einfaches Beispiel dessen, was passieren könnte:
Die beiden Zeilen mit der Berechnung werden vom Preprozessor folgendermassen umgewandelt:
Damit ist klar, dass bei der ersten Zeile nur Die Fehler bei vergessener Klammerung von Casts können noch schlimmer ausfallen, sobald sie im Zusammenhang mit Pointer-Umwandlungen gebraucht werden, das Programm kann hierbei sogar abstürzen. es ist zu empfehlen, um das gesamte Makro zusätzliche Klammern hinzuzufügen. Folgendes Beispiel versucht, ein zweidimensionales Array als eindimensionales zu casten:
Die Zeilen werden vom Preprozessor folgendermassen umgewandelt:
Während in den ersten beiden Zeilen strickt nach der von der Programmiersprache vorgegebenen Operatorenreihenfolge zuerst das Element mit Index Klammerung von DereferenzenFolgendes Beispiel zeigt, was passiert, wenn man eine Dereferenzierung nicht korrekt klammert:
Der Preprozessor übersetzt den Code in die folgenden Zeilen:
Während bei der ersten Zeile zuerst das erste Dreier-Tupel
|