Preprocessore C ++
I preprocessori sono le direttive, che danno istruzioni al compilatore di preelaborare le informazioni prima che inizi la compilazione vera e propria.
Tutte le direttive del preprocessore iniziano con # e solo i caratteri spazi bianchi possono apparire prima di una direttiva del preprocessore su una riga. Le direttive del preprocessore non sono istruzioni C ++, quindi non terminano con un punto e virgola (;).
Hai già visto un file #includedirettiva in tutti gli esempi. Questa macro viene utilizzata per includere un file di intestazione nel file di origine.
Ci sono numerose direttive per il preprocessore supportate da C ++ come #include, #define, #if, #else, #line, ecc. Vediamo direttive importanti -
Il preprocessore #define
La direttiva del preprocessore #define crea costanti simboliche. La costante simbolica è chiamata amacro e la forma generale della direttiva è:
#define macro-name replacement-text
Quando questa riga appare in un file, tutte le occorrenze successive della macro in quel file verranno sostituite da testo sostitutivo prima che il programma venga compilato. Ad esempio:
#include <iostream>
using namespace std;
#define PI 3.14159
int main () {
cout << "Value of PI :" << PI << endl;
return 0;
}
Ora, eseguiamo la preelaborazione di questo codice per vedere il risultato assumendo di avere il file del codice sorgente. Quindi compiliamolo con l'opzione -E e reindirizziamo il risultato a test.p. Ora, se controlli test.p, avrà molte informazioni e in fondo troverai il valore sostituito come segue:
$gcc -E test.cpp > test.p
...
int main () {
cout << "Value of PI :" << 3.14159 << endl;
return 0;
}
Macro simili a funzioni
Puoi usare #define per definire una macro che prenderà argomenti come segue:
#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;
}
Se compiliamo ed eseguiamo il codice sopra, questo produrrebbe il seguente risultato:
The minimum is 30
Compilazione condizionale
Esistono diverse direttive che possono essere utilizzate per compilare porzioni selettive del codice sorgente del programma. Questo processo è chiamato compilazione condizionale.
Il costrutto del preprocessore condizionale è molto simile alla struttura di selezione "if". Considera il seguente codice del preprocessore:
#ifndef NULL
#define NULL 0
#endif
È possibile compilare un programma a scopo di debug. Puoi anche attivare o disattivare il debug utilizzando una singola macro come segue:
#ifdef DEBUG
cerr <<"Variable x = " << x << endl;
#endif
Questo fa sì che il file cerristruzione da compilare nel programma se la costante simbolica DEBUG è stata definita prima della direttiva #ifdef DEBUG. Puoi usare la frase #if 0 per commentare una parte del programma come segue:
#if 0
code prevented from compiling
#endif
Proviamo il seguente esempio:
#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;
}
Se compiliamo ed eseguiamo il codice sopra, questo produrrebbe il seguente risultato:
The minimum is 30
Trace: Inside main function
Trace: Coming out of main function
Gli operatori # e ##
Gli operatori del preprocessore # e ## sono disponibili in C ++ e ANSI / ISO C. L'operatore # determina la conversione di un token di testo sostitutivo in una stringa racchiusa tra virgolette.
Considera la seguente definizione di macro:
#include <iostream>
using namespace std;
#define MKSTR( x ) #x
int main () {
cout << MKSTR(HELLO C++) << endl;
return 0;
}
Se compiliamo ed eseguiamo il codice sopra, questo produrrebbe il seguente risultato:
HELLO C++
Vediamo come ha funzionato. È semplice capire che il preprocessore C ++ cambia la linea -
cout << MKSTR(HELLO C++) << endl;
La riga sopra verrà trasformata nella riga seguente:
cout << "HELLO C++" << endl;
L'operatore ## viene utilizzato per concatenare due token. Ecco un esempio:
#define CONCAT( x, y ) x ## y
Quando CONCAT appare nel programma, i suoi argomenti vengono concatenati e utilizzati per sostituire la macro. Ad esempio, CONCAT (HELLO, C ++) viene sostituito da "HELLO C ++" nel programma come segue.
#include <iostream>
using namespace std;
#define concat(a, b) a ## b
int main() {
int xy = 100;
cout << concat(x, y);
return 0;
}
Se compiliamo ed eseguiamo il codice sopra, questo produrrebbe il seguente risultato:
100
Vediamo come ha funzionato. È semplice capire che il preprocessore C ++ trasforma:
cout << concat(x, y);
La riga sopra verrà trasformata nella riga seguente:
cout << xy;
Macro C ++ predefinite
C ++ fornisce una serie di macro predefinite menzionate di seguito:
Suor n | Macro e descrizione |
---|---|
1 | __LINE__ Contiene il numero di riga corrente del programma quando viene compilato. |
2 | __FILE__ Contiene il nome del file corrente del programma quando viene compilato. |
3 | __DATE__ Contiene una stringa della forma mese / giorno / anno che è la data della traduzione del file sorgente in codice oggetto. |
4 | __TIME__ Questo contiene una stringa della forma ora: minuto: secondo che è l'ora in cui il programma è stato compilato. |
Vediamo un esempio per tutte le macro sopra -
#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;
}
Se compiliamo ed eseguiamo il codice sopra, questo produrrebbe il seguente risultato:
Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48