10.3 Bedingte Kompilierung 

Zu diesem Unterkapitel muss erwähnt werden, dass viele der beschriebenen Vorgehensweisen nicht dem ANSI-C-Standard entsprechen. Da aber Programmierer oft ihre Programme auch auf andere Systeme portieren wollen, gehe ich hier dennoch näher auf die Thematik ein. Hierzu betrachten wir die Syntax zur bedingten Übersetzung:
#ifdef symbol #ifdef ( symbol ) #elif symbol #elif ( symbol ) #else #endif
Diese Direktiven werden eingesetzt, um zu überprüfen, ob ein Symbol zuvor schon mit #define definiert wurde. Ist symbol definiert, liefern diese Direktiven 1 zurück, ansonsten 0. Abgeschlossen wird eine bedingte Übersetzung mit der Direktive #endif.
Sie haben im vorangegangenen Kapitel (bei der selbst geschriebenen Headerdatei) schon einen kurzen Einblick in die bedingte Kompilierung erhalten. Hierzu ein einfaches Beispiel:
/* clrscr.c */ #include <stdio.h> #include <stdlib.h> #ifdef __unix__ #define clrscr() printf("\x1B[2J") #elif __BORLANDC__ && __MSDOS__ #include <conio.h> #elif __WIN32__ || _MSC_VER #define clrscr() system("cls") #else #define clrscr() printf("clrscr() - Fehler!!\n") #endif int main(void) { /* universale Routine zum Löschen des Bildschirms */ clrscr(); return EXIT_SUCCESS; }
Hier wird vor der Übersetzung festgelegt, welche Routine zum Löschen des Bildschirms benutzt werden soll. Mit
#ifdef __unix__
überprüft der Präprozessor, ob das Programm auf einem UNIX-artigen System läuft. Wenn das der Fall ist, dann wird mit
#define clrscr() printf("\x1B[2J")
die Routine zum Löschen des Bildschirms definiert, da diese eben nur unter UNIX/Linux funktioniert. Falls es sich nicht um ein UNIX-System handelt, wird mit
#elif __BORLANDC__ && __MSDOS__
überprüft, ob das Programm mit einem Borland-Compiler und unter MS-DOS übersetzt wird. Ist das der Fall, dann wird das Löschen des Bildschirms durch eine in der Headerdatei #include <conio.h> definierte Funktion mit demselbem Namen vorgenommen. Anschließend wird überprüft, ob das Programm in einem Win32-Fenster läuft oder mit dem Visual C++-Compiler übersetzt wird.
#elif __WIN32__ || _MSC_VER #define clrscr() system("cls")
Trifft keiner der geprüften Fälle zu, wird eine entsprechende Ausgabe erzeugt:
#else #define clrscr() printf("clrscr()-Fehler!!\n")
Abgeschlossen wird diese bedingte Kompilierung mit:
#endif
Durch die bedingte Kompilierung besteht die Möglichkeit, Programme einfacher auf andere Systeme zu portieren. Die bedingte Kompilierung lässt sich auch anders verwenden:
/* t_system.c */ #include <stdio.h> #include <stdlib.h> #ifdef __MSDOS__ int main(void) { printf("Programm läuft unter MSDOS \n"); return EXIT_SUCCESS; } #elif __WIN32__ || _MSC_VER int main(void) { printf("Programm läuft unter Win32\n"); return EXIT_SUCCESS; } #elif __unix__ || __linux__ int main(void) { printf("Programm läuft unter UNIX/LINUX\n"); return EXIT_SUCCESS; } #else int main(void) { printf("Unbekanntes Betriebssystem!!\n"); return EXIT_SUCCESS; } #endif
Hier wurden mehrere main()-Funktionen verwendet. Auf dem System, für das die bedingte Kompilierung gilt, wird die entsprechende main-Funktion auch ausgeführt.
Abbildung 10.2 Bedingte Kompilierung – das Programm läuft unter Win32.
Abbildung 10.3 Bedingte Kompilierung – das Programm läuft unter Linux/UNIX.
Sie können die bedingte Kompilierung mit if else-Abfragen vergleichen. Um compiler-spezifische Abfragen zu tätigen, gibt es folgende Compiler-Konstanten:
Konstante | Compiler |
_MSC_VER |
Microsoft C ab Version 6.0 |
_QC |
Microsoft Quick C ab Version 2.51 |
_TURBOC_ |
Borland Turbo C, Turbo C++ und BC++ |
_BORLANDC_ |
Borland C++ |
_ZTC_ |
Zortech C und C++ |
_SC_ |
Symantec C++ |
_WATCOMC_ |
WATCOM C |
_GNUC_ |
Gnu C |
_EMX_ |
Emx Gnu C |
Denken Sie daran, dass diese Konstanten nicht vom ANSI-C-Gremium vorgeschrieben sind!
Für die bedingte Kompilierung mit Betriebssystemen finden sich folgende Konstanten:
Konstante | Betriebssystem |
__unix__ oder __unix |
UNIX-System |
__MS_DOS__ |
MS-DOS |
__WIN32__ |
Windows ab 95 |
__OS2__ |
OS2 |
_Windows |
Zielsystem Windows |
__NT__ |
Windows NT |
__linux__ |
Linux |
__FreeBSD__ |
FreeBSD |
OpenBSD |
OpenBSD |
_SGI_SOURCE |
SGI-IRIX mit Extension *.sgi |
_MIPS_ISA |
SGI-IRIX |
_hpux |
HP-UX |
Es gibt sicherlich noch weitere Konstanten. Die hier genannten zählen zu den gängigsten. Sehen Sie sich ein anderes Programmbeispiel dazu an:
/* sektor.c */ #include <stdio.h> #include <stdlib.h> #ifdef __unix__ || linux #define SEKTORSIZE 4096 #elif __MSDOS__ || __WIN32__ || _MSC_VER #define SEKTORSIZE 512 #else #define SEKTORSIZE 0 #endif void sect(long size) { long kb,s=SEKTORSIZE; if(s == 0) printf("Unbekanntes System\n"); else if(s==4096) printf("UNIXsystem : "); else printf("DOS/Win32 : "); kb = size * s; printf("%ld Sektoren = %ld B\n", size, kb); } int main(void) { long sector; printf("Wie viele Sektoren: "); scanf("%ld",§or); sect(sector); return EXIT_SUCCESS; }
Dies ist ein Beispiel zum Thema Portabilität. Auf MS-DOS/Win32 beträgt die Größe eines Sektors auf der Festplatte 512 KB. Auf UNIX-Systemen hingegen beträgt sie meist 4096 KB (unter BSD für gewöhnlich 1024 KB) pro Sektor. Sie müssen nur am Anfang des Programms dem Präprozessor die Anweisung geben, für welches System er die Größe einer bestimmten Anzahl von Sektoren ausgeben soll.
Folgende Schreibweisen sind im Übrigen identisch:
#ifdef MAKRO /* ist identisch mit */ #if defined MAKRO
Des Weiteren gibt es eine Direktive, die es Ihnen ermöglicht, zu überprüfen, ob etwas nicht definiert wurde:
#ifndef __STDIO_H #define __STDIO_H #endif
Hier überprüft der Präprozessor, ob er die Headerdatei <stdio.h> noch nicht eingebunden hat.
Das ist zum Beispiel erforderlich, wenn mehrere Headerdateien und Module benutzt werden, die <stdio.h> benötigen. Somit würden alle Makros in der Headerdatei <stdio.h> mehrmals definiert werden, was im schlimmsten Fall sogar einen Fehler auslösen kann. Mit der eben geschriebenen Struktur wird dies vermieden.
Auch zu dieser Direktive gibt es eine alternative Schreibweise:
#ifndef MAKRO /* ist dasselbe wie */ #if !defined MAKRO
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.