Come già sottolineato, una direttiva al preprocessore è un'istruzione
diretta al compilatore, che espande l'ambiente di programmazione
stesso.
Le direttive al preprocessore sono dette anche macro e il
preprocessore viene indicato più precisamente col nome di preprocessore
di macro.
In buona sostanza, il preprocessore C è un programma interno al
compilatore, che esamina un file sorgente C e compie determinate
modifiche su di esso, basandosi sulle direttive a lui destinate.
Per ora ci interessiamo solo a due macro, #define e #undef , mentre
altre le tratteremo in seguito.
Molto spesso durante un programma si ha la necessità di sostituire
un valore con un testo.
Ad es. supponiamo di dover creare un programma che utilizzi il valore
matematico pi-greco: sarebbe preferibile utilizzare sempre la stringa
PI_GRECO ad ogni occorrenza del valore, piuttosto che scrivere di
volta in volta il valore 3.1415926536.
E in casi come questo che si rivela molto utile la macro
#define sia per funzionalità che per leggibilità.
La forma generale è:
#define nome-macro testo-sostitutivo
oppure
#define nome-macro
Nel caso dellesempio di pi-greco scriveremo:
#define PI_GRECO 3.1415926536
Luso più frequente di #define in Linux è quello di condizionare
la portabilità del codice, cioè se viene definita una data macro
allora possono essere incluse o meno diverse estensioni della libreria
standard C (glibc); in questo caso il nome-macro deve essere definito
nella glibc.
L'esempio più classico di utilizzo è il seguente:
#define FALSO 0
#define VERO 1
Definendo questa direttiva, nel corpo del programma la macro FALSO
viene sostituita con il valore 0 e la macro VERO con il valore 1.
Questa situazione è simile a quella vista nei Makefile: "Tutte
le volte che una macro viene incontrata, la si sostituisce con il
gesto ad essa corrispondente".
Date unocchiata al seguente esempio che non necessita di ulteriori
spiegazioni:
#include <stdio.h>
#include <stdlib.h>
#define FALSO 0
#define VERO 1
int main(void) {
printf("VERO:%d\n", VERO);
printf("FALSO:%d\nDue:%d\n, FALSO, VERO+1);
return(EXIT_SUCCESS);
}
Un altro caso di #define che abbiamo già usato, inconsapevolemente,
è EXIT_SUCCESS, dichiarato nella libreria standard del C.
Un utile uso di #define è definire i messaggi di errore che si
possono ripetere durante l'esecuzione del programma, ad es.:
#define MSG_ERRORE "This
is I LOVE YOU: try format to save your disk!"
Dopo una tale definizione, una possibile istruzione printf
nel corpo del programma è:
printf(MSG_ERRORE);
Se siete dei buoni osservatori avrete certamente notato che tutte
le macro definite sono maiuscole.
Questa è una convenzione, ormai consolidata tra i programmatori,
che permette, durante la lettura di un programma, di rendersi conto
a prima vista della presenza degli identificatori e quindi delle
sostituzioni.
La direttiva #undef cancella la definizione associata alla
macro da #define.
#define VALORE 1 /* imposto
VALORE a 1 */
#undef VALORE /* ma non mi piace, per esigenze preferisco 2
*/
#define VALORE 2 /* imposto VALORE a 2 */
In questo caso se non fosse stata usata la #undef, avrei causato
un messaggio di errore di "multiple define", ciò significa
che le definizioni:
#define DISPARI 3
#define DISPARI 5
non sono lecite, in quanto la definizione di una macro deve essere
unica.
Dopo che una definizione di macro è stata cancellata con #undef,
ogni sua istanza non attiverà più la sostituzione corrispondente.
Questa possibilità del preprocessore viene solo usata in caso di
compilazione condizionale, che vedremo più avanti durante il corso.
Torna all'indice Generale del corso di Corso di C con Linux di Software Planet