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