|
|
C-PräprozessorDer erste Verarbeitungsschritt bei der Kompilierung eines C/C++-Programmes erfolgt durch den Präprozessor. Dieser verändert den Quelltext, den die späteren Verarbeitungsphasen erhalten, in folgender Hinsicht:
Im Grunde kann man sich den Präprozessor als eine Art Texteditor vorstellen, der die Anweisungen, was er zu tun hat, dem Text entnimmt, den er bearbeitet. In jedem Texteditor gibt es zb. die Funktion 'Suchen und Ersetzen'. Auch im Präprozessor gibt es sie, nur heißt sie dort #define. Alle Anweisungen an den Präprozessor beginnen grundsätzlich damit, daß das Zeichen '#' das erste Zeichen in einer Textzeile darstellt. Und umgekehrt: Ist das erste Zeichen in einer Textzeile ein '#', so handelt es sich um eine Präprozessor-Anweisung.
[Bearbeiten] #includeDie #include weist den Präprozessor an, den Inhalt der angegebenen Datei anstelle der #include Anweisung einzusetzen. Weiter passiert nichts. Bei der Angabe des Dateinamens der einzusetzenden Datei gibt es 2 Formen
Der Unterschied zwischen beiden Formen besteht rein im Aufsuchpfad, den der Präprozessor benutzt, um die Datei zu finden. Per Konvention wird die < >-Form benutzt, um systemweite Includes durchzuführen. Alle mit dem Compiler mitgelieferten Header Files sind zb. solche systemweite-Includes. Bei der Installation des Compilers wurde im System hinterlassen, auf welchem Pfad sie gefunden werden können. Durch Verwendung der < >-Form wird dem Präprozessor mitgeteilt, dass diese damals vereinbarten Pfadangaben zur Aufsuche dieser Datei benutzt werden soll. [Bearbeiten] #defineMittels #define wird eine Textersetzung vereinbart.
weist den Präprozessor an, im weiteren Quelltext alle Vorkommen von 'ABC' durch den Text 'xyz' zu ersetzen. Der Präprozessor macht dies überall, solange
Wichtig ist: Der Präprozessor führt eine reine Textersetzung durch! Ob sich durch diese Ersetzung eine Logikänderung im Programm ergibt, interessiert den Präprozessor nicht.
Bevor der eigentliche Compiler den Quelltext zu Gesicht bekommt, wird er zunächst vom Präprozessor bearbeitet. Dieser führt die Textersetzung durch, indem er alle Vorkommen von NR durch den Text 5 ersetzt. Erst dieses Ergebnis
wird dann dem eigentlichen Compiler zur Übersetzung vorgelegt. In diesem Beispiel hat man durch den Einsatz des Präprozessors erreicht, dass die Anzahl der Arrayelemente immer mit dem Maximalwert in der for-Schleife übereinstimmt. Ein Fehler, dass beispielweise die Arraygröße verändert wird, ohne das die for-Schleife angepasst würde, ist durch den Einsatz des Präprozessors wirkungsvoll verhindert worden. [Bearbeiten] #if, #ifdef[Bearbeiten] mögliche Probleme beim Einsatz des PräprozessorsEine am C-Präprozessor häufig geäußerte Kritik ist, dass er (nahezu) ohne Berücksichtigung der eigentlichen Sprachsyntax arbeitet ("The C-Preprocessor doesn't know about C"). Die Tatsache, dass Makros beispielsweise auf der Basis von Textersatz arbeiten, kann zu Überaschungen führen. So wird in
in x nicht etwa der Wert 125 (5 hoch 3) stehen, sondern der Wert 13, da nach Ersetzen des Makros der folgende Quelltext kompiliert wird ...
... und durch die arithmetischen Vorrangregeln, wird dieser Ausdruck so ausgewertet:
Deshalb sollte man jeden Parameter eines Makros bei jeder Verwendung klammern. Damit werden viele Probleme mit Makros gelöst und man erhält für obiges Beispiel folgende Form und damit auch eine korrekte Berechnung:
Ein weiteres Problem besteht jedoch, wenn ein Makro-Parameter im Ersatztext doppelt verwendet wird:
Im zweiten Fall wird die Variable y u.U. zweimal inkrementiert - was ohne Kenntnis der Makro-Definition keineswegs offensichtlich ist (max könnte auch eine echte Funktion sein). Die Tatsache, dass der C-Präprozessor die Syntax von C/C++ nicht wirklich berücksichtigt, ist allerdings auch nützlich. So lassen sich mit dem C-Präprozessor Datentypen parametrisieren, um systematische Programmteile zu vereinfachen:
Viele typische Anwendungsfälle des Präprozessors lassen sich allerdings bereits mit Standard-C-Bordmitteln erfolgreich erschlagen:
|