Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch für Linux, Unix und Windows
– 2., aktualisierte und erweiterte Auflage 2006
Buch: C von A bis Z

C von A bis Z
1.116 S., mit CD, Referenzkarte, 39,90 Euro
Galileo Computing
ISBN 3-89842-643-2
gp Kapitel 12 Präprozessor-Direktiven
  gp 12.1 Einkopieren von Dateien mittels #include
  gp 12.2 Makros und Konstanten – #define
    gp 12.2.1 Symbolische Konstanten mit #define
    gp 12.2.2 Makros mit #define
  gp 12.3 Bedingte Kompilierung
  gp 12.4 Vordefinierte Präprozessor-Direktiven (ANSI C)
  gp 12.5 Ersetzung eines Makroparameters durch einen String
  gp 12.6 #undef – Makronamen wieder aufheben
  gp 12.7 Ausgeben von Fehlermeldungen – #error
  gp 12.8 #pragma


Galileo Computing - Zum Seitenanfang

12.3 Bedingte Kompilierung  toptop

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 gern auf andere Systeme portieren wollen, soll hier dennoch näher auf die Thematik eingegangen werden. Hierzu 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 schon einen kurzen Einblick (bei der selbst geschriebenen Headerdatei) 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 demselben 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
Hier klicken, um das Bild zu Vergrößern

Abbildung 12.2   Bedingte Kompilierung – Programm läuft unter Win32

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 12.3   Bedingte Kompilierung – Programm läuft unter Linux/UNIX

Sie können die bedingte Kompilierung mit if-else if–else-Abfragen vergleichen. Um Compiler-spezifische Abfragen zu tätigen, gibt es folgende Compiler-Konstanten:


Tabelle 12.3   Konstanten für bestimmte Compiler

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

Es wird nochmals darauf hingewiesen, dass diese Konstanten nicht vom ANSI C-Gremium vorgeschrieben sind.

Für die bedingte Kompilierung mit Betriebssystemen finden sich folgende Konstanten:


Tabelle 12.4   Konstanten für bestimmte Betriebssysteme

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",&sector);
   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 KBytes. Auf UNIX-Systemen hingegen meist 4096 KBytes (unter BSD gewöhnlich 1024 KBytes) 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 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 dieses vermieden.

Auch zu dieser Direktive gibt es eine alternative Schreibweise:

#ifndef MAKRO
/* ist dasselbe wie */
#if !defined MAKRO
 << zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z
C von A bis Z
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-UNIX-Programmierung






 Linux-UNIX-Programmierung


Zum Katalog: C/C++






 C/C++


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Reguläre Ausdrücke






 Reguläre Ausdrücke


Zum Katalog: Linux






 Linux


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de