C - Preprocessori

Il C Preprocessornon fa parte del compilatore, ma è un passaggio separato nel processo di compilazione. In termini semplici, un preprocessore C è solo uno strumento di sostituzione del testo e istruisce il compilatore a eseguire la pre-elaborazione richiesta prima della compilazione effettiva. Faremo riferimento al preprocessore C come CPP.

Tutti i comandi del preprocessore iniziano con un simbolo cancelletto (#). Deve essere il primo carattere non vuoto e, per la leggibilità, una direttiva per il preprocessore dovrebbe iniziare nella prima colonna. La sezione seguente elenca tutte le direttive importanti per il preprocessore:

Sr.No. Direttiva e descrizione
1

#define

Sostituisce una macro del preprocessore.

2

#include

Inserisce una particolare intestazione da un altro file.

3

#undef

Annulla la definizione di una macro del preprocessore.

4

#ifdef

Restituisce vero se questa macro è definita.

5

#ifndef

Restituisce vero se questa macro non è definita.

6

#if

Verifica se una condizione del tempo di compilazione è vera.

7

#else

L'alternativa per #if.

8

#elif

#else e #if in un'unica istruzione.

9

#endif

Termina il condizionale del preprocessore.

10

#error

Stampa un messaggio di errore su stderr.

11

#pragma

Emette comandi speciali al compilatore, utilizzando un metodo standardizzato.

Esempi di preprocessori

Analizza i seguenti esempi per comprendere le varie direttive.

#define MAX_ARRAY_LENGTH 20

Questa direttiva dice al CPP di sostituire le istanze di MAX_ARRAY_LENGTH con 20. Usa #define per le costanti per aumentare la leggibilità.

#include <stdio.h>
#include "myheader.h"

Queste direttive indicano al CPP di ottenere stdio.h da System Librariese aggiungi il testo al file sorgente corrente. La riga successiva dice a CPP di otteneremyheader.h dalla directory locale e aggiungere il contenuto al file di origine corrente.

#undef  FILE_SIZE
#define FILE_SIZE 42

Indica al CPP di annullare la definizione di FILE_SIZE esistente e definirlo come 42.

#ifndef MESSAGE
   #define MESSAGE "You wish!"
#endif

Indica al CPP di definire MESSAGGIO solo se MESSAGGIO non è già definito.

#ifdef DEBUG
   /* Your debugging statements here */
#endif

Indica al CPP di elaborare le istruzioni incluse se DEBUG è definito. Questo è utile se passi il flag -DDEBUG al compilatore gcc al momento della compilazione. Questo definirà DEBUG, quindi puoi attivare e disattivare il debug al volo durante la compilazione.

Macro predefinite

ANSI C definisce un numero di macro. Sebbene ognuno sia disponibile per l'uso nella programmazione, le macro predefinite non devono essere modificate direttamente.

Sr.No. Macro e descrizione
1

__DATE__

La data corrente come valore letterale carattere nel formato "MMM GG AAAA".

2

__TIME__

L'ora corrente come carattere letterale nel formato "HH: MM: SS".

3

__FILE__

Contiene il nome del file corrente come stringa letterale.

4

__LINE__

Contiene il numero di riga corrente come costante decimale.

5

__STDC__

Definito come 1 quando il compilatore è conforme allo standard ANSI.

Proviamo il seguente esempio:

#include <stdio.h>

int main() {

   printf("File :%s\n", __FILE__ );
   printf("Date :%s\n", __DATE__ );
   printf("Time :%s\n", __TIME__ );
   printf("Line :%d\n", __LINE__ );
   printf("ANSI :%d\n", __STDC__ );

}

Quando il codice sopra in un file test.c viene compilato ed eseguito, produce il seguente risultato:

File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
ANSI :1

Operatori del preprocessore

Il preprocessore C offre i seguenti operatori per aiutare a creare macro:

Operatore di continuazione macro (\)

Una macro è normalmente limitata a una singola riga. L'operatore di continuazione della macro (\) viene utilizzato per continuare una macro troppo lunga per una singola riga. Ad esempio:

#define  message_for(a, b)  \
   printf(#a " and " #b ": We love you!\n")

L'operatore Stringize (#)

L'operatore stringize o number-sign ('#'), se utilizzato all'interno di una definizione di macro, converte un parametro macro in una costante di stringa. Questo operatore può essere utilizzato solo in una macro con un argomento o un elenco di parametri specificato. Ad esempio:

#include <stdio.h>

#define  message_for(a, b)  \
   printf(#a " and " #b ": We love you!\n")

int main(void) {
   message_for(Carole, Debra);
   return 0;
}

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

Carole and Debra: We love you!

L'operatore Token Pasing (##)

L'operatore di incolla token (##) all'interno di una definizione di macro combina due argomenti. Consente di unire due token separati nella definizione della macro in un unico token. Ad esempio:

#include <stdio.h>

#define tokenpaster(n) printf ("token" #n " = %d", token##n)

int main(void) {
   int token34 = 40;
   tokenpaster(34);
   return 0;
}

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

token34 = 40

È successo così perché questo esempio si traduce nel seguente output effettivo dal preprocessore:

printf ("token34 = %d", token34);

Questo esempio mostra la concatenazione del token ## n in token34 e qui abbiamo usato entrambi stringize e token-pasting.

L'operatore Defined ()

Il preprocessore definedL'operatore viene utilizzato nelle espressioni costanti per determinare se un identificatore è definito utilizzando #define. Se l'identificatore specificato è definito, il valore è vero (diverso da zero). Se il simbolo non è definito, il valore è falso (zero). L'operatore definito è specificato come segue:

#include <stdio.h>

#if !defined (MESSAGE)
   #define MESSAGE "You wish!"
#endif

int main(void) {
   printf("Here is the message: %s\n", MESSAGE);  
   return 0;
}

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

Here is the message: You wish!

Macro parametrizzate

Una delle potenti funzioni del CPP è la capacità di simulare funzioni utilizzando macro parametrizzate. Ad esempio, potremmo avere un codice per quadrare un numero come segue:

int square(int x) {
   return x * x;
}

Possiamo riscrivere sopra il codice usando una macro come segue:

#define square(x) ((x) * (x))

Le macro con argomenti devono essere definite utilizzando l'estensione #defineprima che possano essere utilizzati. L'elenco degli argomenti è racchiuso tra parentesi e deve seguire immediatamente il nome della macro. Non sono consentiti spazi tra il nome della macro e la parentesi aperta. Ad esempio:

#include <stdio.h>

#define MAX(x,y) ((x) > (y) ? (x) : (y))

int main(void) {
   printf("Max between 20 and 10 is %d\n", MAX(10, 20));  
   return 0;
}

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

Max between 20 and 10 is 20