12.3. Bedingte Kompilierung

Bedingte Kompilierung ermöglicht dem Programmierer, die Ausführung von Preprozessor-Anweisungen und die Übersetzung bestimmter Programmteile vom Zutreffen einer Bedingung abhängig zu machen. Für diesen Zweck steht die Preprozessor-Anweisung #if zur Verfügung, die nach dem Muster der if-Konstruktion in C funktioniert:


#if SIZE <= 127
	#undef SIZE
	#define SIZE 256
#endif

Eine #if-Konstruktion muß immer mit einem #endif abgeschlossen werden. In unserem Beispiel wird SIZE nur dann neu definiert, wenn SIZE ein symbolischer Name für eine Konstante <= 127 wäre. In der #if-Bedingung dürfen nur Konstanten vorkommen, da ja der Preprozessor den Quellcode vor dem Compiler auswertet und daher nicht die Wertänderungen von Variablen, die erst während der Laufzeit stattfinden, berücksichtigen kann.

Besonderer Beliebtheit erfreut sich die #if-Anweisung bei der Fehlersuche; #if macht es nämlich möglich, ganze Programmteile von der Kompilierung auszunehmen. Auf diese Art können in einer Debug-Version z.B. printf()-Anweisungen die Werte von bestimmten Variablen ausdrucken. In der endgültigen Version müssen diese Anweisungen nicht gelöscht, sondern nur über die #if-Bedingung ausgeschlossen werden:


#if 0
	/* Keine der Anweisungen zwischen #if
	 * und #endif würde vom Compiler übersetzt
	 */
	printf("Wert von iCount: %d", iCount);
	.
	 .
#endif

Da die Bedingung 0 immer falsch ist, übergibt der Preprozessor an den Compiler eine Temporärdatei, in der alle Anweisungen des #if-Körpers entfernt wurden. Diese Vorgehensweise ist dem "Auskommentieren

"

von Programmteilen vorzuziehen. Beim sogenannten "Auskommentieren" besteht immer die Gefahr, daß betroffene Programmteile Kommentare enthalten und so versehentlich unzulässige verschachtelte Kommentare entstehen.

Soll die Übersetzung mehrerer verstreuter Anweisungen für die Fehlersuche ein- oder ausgeschaltet werden, dann müßten Sie beim eben gezeigten Vorgehen je nach Bedarf bei jedem #if den Wert 0 gegen 1 austauschen und umgekehrt. Einfacher geht es, indem Sie bei allen #if-Anweisungen die Existenz einer bestimmten symbolischen Konstante abfragen. Dies geschieht mit der Anweisung #ifdef bzw. #ifndef. Die erste der beiden gibt den Wert "wahr

" zurück

, falls die betreffende symbolische Konstante definiert wurde, die zweite gibt "wahr" zurück, falls eine solche nicht definiert wurde. Dabei ist es völlig gleichgültig, welchen Wert diese Konstante hat oder ob sie überhaupt einen Wert hat: Sie muß nur dem Preprozessor bekannt sein:


#define DEBUG

#ifdef DEBUG
	/* Da DEBUG definiert wurde, werden alle
	 * Anweisungen zwischen #if und #endif
	 * vom Compiler übersetzt
	 */
	printf("Wert von iCount: %d", iCount);
	.
	 .
#endif

Offensichtlich genügt hier ein #undef DEBUG oder das Löschen der Zeile #define DEBUG, um die Bedingung aller nachfolgenden #ifdef DEBUG ungültig bzw. falsch zu machen.

Die #if-Anweisung kann bei Bedarf einen #else-Zweig aufweisen und sogar zu einer else-if Kaskade erweitert werden; für letztere steht die Anweisung #elif zur Verfügung. Eine #if/#else-Konstruktion kann dazu beitragen, die Portierbarkeit eines Programms zu erhöhen. Sollen compiler-spezifische Spracherweiterungen oder Funktionen verwendet werden, die nicht vom ANSI-Standard definiert sind, dann können verschiedene Plattformen berücksichtigt werden, indem Sie Programmblöcke bedingt übersetzen lassen. Wenn Sie beispielsweise den Bildschirm löschen wollen, dann steht dafür keine ANSI-konforme Funktion zur Verfügung. Damit ein Programm aber trotzdem auf verschiedenen Plattformen übersetzt werden kann, bietet sich folgende Lösung an:


#ifdef BORLAND
	#include <conio.h>
	#define CLEAR() clrscr()
#elif defined MICROSOFT
	#include <graph.h>
	#define CLEAR() _clearscreen(0)
#elif defined UNIX
	#include <curses.h>
	#define CLEAR() clear()
#endif

Ein einfaches #define BORLAND würde genügen, damit ein Programm mit dieser #if-Konstruktion unter Turbo C oder Borland C korrekt kompiliert werden kann. Bei defined handelt es sich um ein Schlüsselwort, das Sie nicht als symbolischen Namen in Ihren eigenen #define-Anweisungen vergeben dürfen: #if defined ist gleichbedeutend mit #ifdef.