Preprocesor C ++
Preprocesory to dyrektywy, które przekazują kompilatorowi instrukcje dotyczące wstępnego przetworzenia informacji przed rozpoczęciem właściwej kompilacji.
Wszystkie dyrektywy preprocesora zaczynają się od #, a przed dyrektywą preprocesora w wierszu mogą pojawić się tylko znaki odstępu. Dyrektywy preprocesora nie są instrukcjami C ++, więc nie kończą się średnikiem (;).
Widziałeś już #includedyrektywy we wszystkich przykładach. To makro służy do dołączania pliku nagłówkowego do pliku źródłowego.
Istnieje wiele dyrektyw preprocesora obsługiwanych przez C ++, takich jak #include, #define, #if, #else, #line, itd. Zobaczmy ważne dyrektywy -
#Define Preprocessor
Dyrektywa #define preprocesora tworzy symboliczne stałe. Symboliczna stała nazywana jest amacro a ogólna forma dyrektywy to -
#define macro-name replacement-text
Kiedy ta linia pojawi się w pliku, wszystkie kolejne wystąpienia makra w tym pliku zostaną zastąpione tekstem zastępczym przed skompilowaniem programu. Na przykład -
#include <iostream>
using namespace std;
#define PI 3.14159
int main () {
cout << "Value of PI :" << PI << endl;
return 0;
}
Teraz wykonajmy wstępne przetwarzanie tego kodu, aby zobaczyć wynik, zakładając, że mamy plik kodu źródłowego. Skompilujmy go więc z opcją -E i przekierujmy wynik do test.p. Teraz, jeśli zaznaczysz test.p, będzie on zawierał wiele informacji, a na dole znajdziesz wartość zamienioną w następujący sposób -
$gcc -E test.cpp > test.p
...
int main () {
cout << "Value of PI :" << 3.14159 << endl;
return 0;
}
Makra podobne do funkcji
Możesz użyć #define, aby zdefiniować makro, które będzie przyjmować argument w następujący sposób -
#include <iostream>
using namespace std;
#define MIN(a,b) (((a)<(b)) ? a : b)
int main () {
int i, j;
i = 100;
j = 30;
cout <<"The minimum is " << MIN(i, j) << endl;
return 0;
}
Jeśli skompilujemy i uruchomimy powyższy kod, dałoby to następujący wynik -
The minimum is 30
Kompilacja warunkowa
Istnieje kilka dyrektyw, których można użyć do kompilacji wybranych fragmentów kodu źródłowego programu. Ten proces nazywa się kompilacją warunkową.
Konstrukcja preprocesora warunkowego jest podobna do struktury selekcji „if”. Rozważmy następujący kod preprocesora -
#ifndef NULL
#define NULL 0
#endif
Możesz skompilować program do celów debugowania. Możesz także włączyć lub wyłączyć debugowanie za pomocą jednego makra w następujący sposób -
#ifdef DEBUG
cerr <<"Variable x = " << x << endl;
#endif
To powoduje cerrinstrukcja do wkompilowania w programie, jeśli stała symboliczna DEBUG została zdefiniowana przed dyrektywą #ifdef DEBUG. Możesz użyć instrukcji #if 0, aby skomentować część programu w następujący sposób -
#if 0
code prevented from compiling
#endif
Wypróbujmy następujący przykład -
#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: Inside main function" << endl;
#endif
#if 0
/* This is commented part */
cout << MKSTR(HELLO C++) << endl;
#endif
cout <<"The minimum is " << MIN(i, j) << endl;
#ifdef DEBUG
cerr <<"Trace: Coming out of main function" << endl;
#endif
return 0;
}
Jeśli skompilujemy i uruchomimy powyższy kod, dałoby to następujący wynik -
The minimum is 30
Trace: Inside main function
Trace: Coming out of main function
Operatory # i ##
Operatory preprocesorów # i ## są dostępne w językach C ++ i ANSI / ISO C. Operator # powoduje, że token zastępujący tekst jest konwertowany na ciąg w cudzysłowie.
Rozważ następującą definicję makra -
#include <iostream>
using namespace std;
#define MKSTR( x ) #x
int main () {
cout << MKSTR(HELLO C++) << endl;
return 0;
}
Jeśli skompilujemy i uruchomimy powyższy kod, dałoby to następujący wynik -
HELLO C++
Zobaczmy, jak to działało. Łatwo zrozumieć, że preprocesor C ++ zmienia linię -
cout << MKSTR(HELLO C++) << endl;
Powyższa linia zostanie zamieniona w następującą linię -
cout << "HELLO C++" << endl;
Operator ## służy do łączenia dwóch tokenów. Oto przykład -
#define CONCAT( x, y ) x ## y
Gdy w programie pojawi się CONCAT, jego argumenty są łączone i używane do zastąpienia makra. Na przykład CONCAT (HELLO, C ++) jest zastępowane w programie przez „HELLO C ++” w następujący sposób.
#include <iostream>
using namespace std;
#define concat(a, b) a ## b
int main() {
int xy = 100;
cout << concat(x, y);
return 0;
}
Jeśli skompilujemy i uruchomimy powyższy kod, dałoby to następujący wynik -
100
Zobaczmy, jak to działało. Łatwo zrozumieć, że preprocesor C ++ przekształca -
cout << concat(x, y);
Powyższa linia zostanie przekształcona w następującą linię -
cout << xy;
Wstępnie zdefiniowane makra C ++
C ++ udostępnia szereg wstępnie zdefiniowanych makr wymienionych poniżej -
Sr.No | Makro i opis |
---|---|
1 | __LINE__ Zawiera aktualny numer wiersza programu podczas kompilacji. |
2 | __FILE__ Zawiera aktualną nazwę pliku programu podczas kompilacji. |
3 | __DATE__ Zawiera ciąg w postaci miesiąc / dzień / rok, który jest datą tłumaczenia pliku źródłowego na kod wynikowy. |
4 | __TIME__ Zawiera ciąg w postaci godzina: minuta: sekunda, czyli czas, w którym program został skompilowany. |
Zobaczmy przykład dla wszystkich powyższych makr -
#include <iostream>
using namespace std;
int main () {
cout << "Value of __LINE__ : " << __LINE__ << endl;
cout << "Value of __FILE__ : " << __FILE__ << endl;
cout << "Value of __DATE__ : " << __DATE__ << endl;
cout << "Value of __TIME__ : " << __TIME__ << endl;
return 0;
}
Jeśli skompilujemy i uruchomimy powyższy kod, dałoby to następujący wynik -
Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48