C++ Präprozessor

Präprozessoren sind Direktiven, die den Compiler anweisen, die vor der eigentlichen Kompilierung erforderliche Vorverarbeitung durchzuführen.

Alle Präprozessor-Direktiven beginnen mit dem Rautezeichen (#). Vor einer Präprozessor-Direktive dürfen nur Leerraumzeichen stehen. Präprozessor-Direktiven sind keine C++-Anweisungen, daher enden sie nicht mit einem Semikolon (;).

Wir haben gesehen, dass in allen vorherigen Beispielen#include-Direktive. Dieses Makro wird verwendet, um eine Header-Datei in die Quelldatei einzubinden.

C++ unterstützt auch viele Präprozessor-Direktiven wie #include, #define, #if, #else, #line usw. Werfen wir einen Blick auf diese wichtigen Direktiven.

#define Präprozessor

Die #define-Präprozessor-Direktive wird verwendet, um symbolische Konstanten zu erstellen. Diese symbolische Konstante wird oftMakrogenannt. Die allgemeine Form der Direktive ist:

#define macro-name replacement-text 

Wenn diese Codezeile in einer Datei auftritt, werden alle nachfolgenden Vorkommen des Makros in dieser Datei durch replacement-text ersetzt, bevor das Programm kompiliert wird. Zum Beispiel:

#include <iostream> using namespace std; # PI 3.14159 int main () { cout << "Wert von PI :" << PI << endl; return 0; }

Nun wollen wir diesen Code testen, um das Ergebnis der Vorverarbeitung zu sehen. Angenommen, die Quelldatei existiert bereits, verwenden Sie als Nächstes die Option -E zum Kompilieren und leiten Sie das Ergebnis nach test.p um. Wenn Sie sich nun die Datei test.p ansehen, werden Sie feststellen, dass sie bereits eine große Menge an Informationen enthält und der Wert am Ende der Datei wie folgt geändert wurde:

$ gcc -E test.cpp > test.p

...
int main ()
{
 
    cout << "Value of PI :" << 3.14159 << endl; 

    return 0;
}

Parametrisiertes Makro

Sie können #define verwenden, um ein Makro mit Parametern zu definieren, wie folgt:

#include <iostream> using namespace std; #define MIN(a,b) (a<b ? a : b) int main () { int i, j; i = 100; j = 30; cout <<"Der kleinere Wert ist:" << MIN(i, j) << endl; return 0; }

Wenn der obige Code kompiliert und ausgeführt wird, liefert er die folgenden Ergebnisse:

较小的值为:30

Bedingte Kompilierung

Es gibt mehrere Direktiven, mit denen Teile des Programmquellcodes selektiv kompiliert werden können. Dieser Vorgang wird bedingte Kompilierung genannt.

Die Struktur des bedingten Präprozessors ist der if-Auswahlstruktur sehr ähnlich. Sehen Sie sich den folgenden Präprozessorcode an:

#ifdef NULL
   #define NULL 0
#endif

Sie können nur während des Debuggens kompilieren. Der Debug-Schalter kann mit einem Makro implementiert werden, wie folgt:

#ifdef DEBUG
   cerr <<"Variable x = " << x << endl;
#endif

Wenn die symbolische Konstante DEBUG vor der Direktive #ifdef DEBUG definiert wurde, dann werden die Anweisungen im ProgrammcerrAnweisungen kompiliert. Sie können die Anweisung #if 0 verwenden, um einen Teil des Programms auszukommentieren, wie folgt:

#if 0
   不进行编译的代码
#endif

Probieren wir das folgende Beispiel aus:

Beispiel

#include <iostream> using namespace std; #define DEBUG #define MIN(a,b) (((a)<(b)) ? a : b) int main () { int i, j; i = 100; j = 30; #ifdef DEBUG cerr <<"Trace: Innerhalb der main-Funktion" << endl; #endif #if 0 /*Dies ist der Kommentarbereich*/ cout << MKSTR(HELLO C++) << endl; #endif cout <<"Das Minimum ist " << MIN(i, j) << endl; #ifdef DEBUG cerr <<"Trace: Verlassen der main-Funktion" << endl; #endif return 0; }

Wenn der obige Code kompiliert und ausgeführt wird, liefert er die folgenden Ergebnisse:

Trace: Inside main function
The minimum is 30
Trace: Coming out of main function

Die Operatoren # und ##

Die Präprozessoroperatoren # und ## sind sowohl in C++ als auch in ANSI/ISO C verfügbar. Der #-Operator wandelt ein Ersetzungstext-Token in eine in Anführungszeichen eingeschlossene Zeichenkette um.

Betrachten Sie die folgende Makrodefinition:

Beispiel

#include <iostream> using namespace std; #define MKSTR( x ) #x int main () { cout << MKSTR(HELLO C++) << endl; return 0; }

Wenn der obige Code kompiliert und ausgeführt wird, liefert er die folgenden Ergebnisse:

HELLO C++

Sehen wir uns an, wie es funktioniert. Es ist nicht schwer zu verstehen, dass der C++-Präprozessor die folgende Zeile nimmt:

cout << MKSTR(HELLO C++) << endl;

Umgewandelt in:

cout << "HELLO C++" << endl;

Der ##-Operator wird verwendet, um zwei Tokens zu verketten. Hier ist ein Beispiel:

#define CONCAT( x, y )  x ## y

Wenn CONCAT im Programm erscheint, werden seine Argumente verkettet und zum Ersetzen des Makros verwendet. Zum Beispiel würde CONCAT(HELLO, C++) im Programm durch "HELLO C++" ersetzt, wie im folgenden Beispiel gezeigt.

Beispiel

#include <iostream> using namespace std; #define concat(a, b) a ## b int main() { int xy = 100; cout << concat(x, y); return 0; }

Wenn der obige Code kompiliert und ausgeführt wird, liefert er die folgenden Ergebnisse:

100

Sehen wir uns an, wie es funktioniert. Es ist nicht schwer zu verstehen, dass der C++-Präprozessor die folgende Zeile nimmt:

cout << concat(x, y);

Umgewandelt in:

cout << xy;

Vordefinierte Makros in C++

C++ stellt einige vordefinierte Makros bereit, die in der folgenden Tabelle aufgeführt sind:

Makro Beschreibung
__LINE__ Dies enthält die aktuelle Zeilennummer, wenn das Programm kompiliert wird.
__FILE__ Dies enthält den aktuellen Dateinamen, wenn das Programm kompiliert wird.
__DATE__ Dies enthält eine Zeichenkette im Format Monat/Tag/Jahr, die das Datum darstellt, an dem die Quelldatei in Objektcode umgewandelt wird.
__TIME__ Dies enthält eine Zeichenkette in der Form Stunde:Minute:Sekunde, die den Zeitpunkt darstellt, zu dem das Programm kompiliert wurde.

Sehen wir uns die Beispiele der oben genannten Makros an:

Beispiel

#include <iostream> using namespace std; int main () { cout << "Wert von __LINE__ : " << __LINE__ << endl; cout << "Wert von __FILE__ : " << __FILE__ << endl; cout << "Wert von __DATE__ : " << __DATE__ << endl; cout << "Wert von __TIME__ : " << __TIME__ << endl; return 0; }

Wenn der obige Code kompiliert und ausgeführt wird, liefert er die folgenden Ergebnisse:

Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48
Weitere Erweiterungen