Makros in C
Ein C-Makro ist ein Bezeichner, dem man mittels #define-Direktive einen Wert, einen Ausdruck, oder allgemeiner ein Codefragment zuordnet, in der Form #define makro_name ausdruck, z.B. #define N 100.
Einfache Makros verwenden
Die Makro-Deklaration erfolgt mittels #define-Direktive und wird an den Anfang des Programms gestellt,
noch vor die main-Funktion, außerhalb aller Funktionen.
Der Makro-Aufruf erfolgt im Quellcode, überall dort, wo man das Makro benötigt, durch Angabe des Makro-Bezeichners
und ggf. passender Argumente.
Makros werden noch vor dem Compilieren durch den Präprozessor expandiert, d.h. jedes Auftreten eines Makros im
Code wird durch den entsprechenden Ausdruck ersetzt. Somit können Makros verschachtelt werden.
#include <stdio.h>
#define QUADRAT(x) ((x)*(x))
#define MITTEL(x,y) (((x)+(y))/2.0)
int main(void) {
printf("3^2 = %d\n", QUADRAT(3));
printf("(4+10)/2 = %f\n", MITTEL(4, 10));
printf("(2^2 + 3^2) / 2 = %f\n", MITTEL(QUADRAT(2), QUADRAT(3))); // 6.5
}
Bei der Verwendung von Makros sollte die korrekte Syntax besonders genau beachtet werden, insbesondere sollte man
den Ausdruck und die Argumente in Klammern setzen, da sonst schwer nachvollziehbare Fehler auftreten.
Um Makros im Code auf den ersten Blick zu erkennen, sollte eine einheitliche Konvention für die Bezeichner verwendet werden.
Wir verwenden hier z.B. durchgehend Großbuchstaben für Makros.
Vordefinierte Makros
In C gibt es einige vordefinierte Makros, diese erkennt man daran, dass ihr Bezeichner mit 2 Unterstrichen beginnt und endet: __FILE__ - Name der aktuellen C-Datei, __DATE__, __TIME__ - Datum und Uhrzeit zum Zeitpunkt des Ausführens des Präprozessors.
printf("Dateiname: %s, Datum und Uhrzeit: %s, %s\n",
(__FILE__), (__DATE__), (__TIME__));
Komplexere Makros verwenden
Komplexere C-Makros haben mehrere Argumente und enthalten Schleifen oder Funktionsaufrufe, hier werden weitere Direktiven (#if, #elif, #else, #endif) und Regeln eingesetzt.
Bedingte Makros mit #ifndef und #endif werden verwendet, um das mehrfache Inkludieren von Header-Dateien zu verhindern. In dem folgenden Beispiel wird der Code in Zeilen 3-5 der Headerdatei nur ausgeführt, wenn das Makro MYLIB_H noch nicht definiert ist, also nur beim ersten Inkludieren der Headerdatei.
/* mylib.h */
#ifndef MYLIB_H
#define MYLIB_H
void trennzeile(char z, int n);
// Weitere selbstdefinierte Funktionen
#endif
/* main.c */
#include <stdio.h>
#include "mylib.h"
#include "mylib.h" // Kein Problem, das doppelte Inkludieren wurde verhindert!
int main(void) {
trennzeile('*', 10);
}
Makros in der Praxis
Makros werden auf unterschiedliche Weise eingesetzt: um Konstanten zu definieren, um eigene Bezeichner für häufig verwendeten Code zu vergeben, oder um kontextabhängigen Code zu programmieren. Makros werden erst stärker eigesetzt, wenn man größere eigene C-Bibliotheken entwickelt. Dann schreibt man eigene Header-Dateien und eigene Logger, schreibt Code für unterschiedliche Betriebssysteme, und wird auch verschiedene Makros benötigen, die dies unterstützen.