Bedingte Compilierung

Bisher war der Zweck des Präprozessors eher fragwürdig. Dadurch, dass er nur Inhalte in den Quelltext kopiert, ist er nicht besonders nützlich. Wenn es aber um die bedingte Compilierung geht, so ist der Präprozessor (sogar in C++) ein sinnvolles Hilfsmittel. Es bedeutet soviel, dass gewisse Teile des Quelltextes vor dem Compiliervorgang vom Präprozessor entfernt werden. Das hat den Vorteil, dass der Quelltext eines Programms, welches für zwei oder mehr Betriebssysteme bestimmt ist, nur einmal geschrieben werden muss. Ähnlich wie eine Wenn-dann-sonst-Anweisung sieht die Syntax des Präprozessors aus.

#include<stdio.h>
 
#define PRINT
 
int main()
{
#ifdef PRINT
    printf("Dieser Text wird angezeigt");
#endif
#ifndef PRINT
    printf("Dieser Text wird nicht angezeigt");
#endif
    return 0;
}

In diesem Programm wird die zweite printf()-Funktion nicht compiliert. Die Konstante PRINT hat keinen Wert, daher wird sie auch als Symbol bezeichnet. Sie dient lediglich dem Präprozessor als Hinweis, ob er gewisse Teile des Quelltextes lassen oder entfernen soll. #ifdef bedeutet soviel wie, „Ist … definiert, dann …“. Es ist abgeleitet aus #if defined, was auch möglich ist. #ifndef bedeutet soviel wie, „Ist … nicht definiert, dann …“ und setzt sich aus #if !defined zusammen, was ebenfalls möglich ist. #endif ist ein Symbol für den Präprozessor, dass er ab dieser Stelle keinen Einfluss mehr auf den Quelltext hat, sofern es keine weitere Bedingung mehr gibt. Würde man #endif weglassen, so würde der Präprozessor, sofern die Bedingung nicht erfüllt ist, den gesamten Quelltext ab der Bedingung abschneiden. Je nach Compiler kann es vorkommen, dass der Präprozessor keine eigene Fehlermeldung ausgibt, dafür aber der Compiler eine Meldung, dass z.B. main() nicht richtig beendet wurde, weil eine geschweifte Klammer fehlt. Die gängigen Compiler sorgen aber dafür, dass der Präprozessor meldet, dass #endif fehlt. Es gibt noch die Anweisungen #else und #elif (else if). Wie auch normale Bedingungen lassen sich Präprozessorbedingungen schachteln. Dabei sollte immer auf #endif geachtet werden.

Es lassen sich aber auch Bedingungen aufstellen, in denen Werte überprüft werden. Dazu nutzt man #if.

#include<stdio.h>
 
#define FALSE 0
#define TRUE 1
 
int main(){
#if FALSE && TRUE
    printf("Nicht logisch");
#elif FALSE || TRUE
    printf("Logisch");
#elif TRUE > FALSE
    printf("TRUE ist größer");
#else
    #error "Fehler"
#endif
#undef TRUE
#ifndef TRUE
    printf("TRUE wurde gelöscht");
#endif
    return 0;
}

Wie man sieht, sind in solchen Abfragen boolesche Operatoren und Vergleichsoperatoren gültig. In diesem Beispiel kam ein neuer Befehl hinzu: #undef Damit kann man Konstanten, Makros und Symbole löschen. Dieser Befehl ist sinnvoll, wenn man in einem Programm Funktionen und Makros mit dem selben Namen hat und man bestimmen will, wann was eingesetzt wird. Allerdings ist solch ein Programmierstil nicht unbedingt empfehlenswert, zumal Funktionen klein und Makros groß geschrieben werden sollten. Wird #error ausgeführt, so wird das Programm nicht compiliert und es erscheint eine Fehlermeldung, in diesem Fall einfach „Fehler“.