Äîêóìåíò âçÿò èç êýøà ïîèñêîâîé ìàøèíû. Àäðåñ îðèãèíàëüíîãî äîêóìåíòà : http://www.arcetri.astro.it/irlab/doc/library/linux/AppLinux/al167.htm
Äàòà èçìåíåíèÿ: Tue Sep 21 18:08:48 1999
Äàòà èíäåêñèðîâàíèÿ: Sat Dec 22 13:24:09 2007
Êîäèðîâêà:

Ïîèñêîâûå ñëîâà: ï ï ï ï ï ï
Appunti Linux: C: istruzioni del preprocessore [inizio] [indice generale] [precedente] [successivo] [indice analitico] [contributi]

130. C: istruzioni del preprocessore

Il preprocessore Õ un programma, o quella parte del compilatore, che si occupa di pre-elaborare un sorgente prima della compilazione vera e propria. In pratica, permette di generare un nuovo sorgente prima che questo venga compilato effettivamente. L'utilitÞ della presenza di un preprocessore, tra le altre cose, sta nella possibilitÞ di definire gruppi di istruzioni alternativi a seconda di circostanze determinate.

Il linguaggio C non puÐ fare a meno della presenza di un preprocessore, e anche le sue direttive sono state regolate con lo standard ANSI.

130.1 Linguaggio a sÈ stante

Le direttive del preprocessore rappresentano un linguaggio a sÈ stante, con le sue regole particolari. In generale:

Nelle sezioni seguenti vengono descritte le direttive piÛ importanti.

130.1.1 Direttiva #include

#include <<file>>

#include "<file>"

La direttiva #include permette di includere un file. Generalmente si tratta di un cosiddetto file di intestazione, contenente una serie di definizioni necessarie al file sorgente in cui vengono incorporate.

Come si vede dalla sintassi, il file puÐ essere indicato delimitandolo con le parentesi angolari, oppure con gli apici doppi.

#include <stdio.h>

#include "stdio.h"

Nel primo caso si fa riferimento a un file che dovrebbe trovarsi in una posizione stabilita dalla configurazione del compilatore (nel caso del C GNU in GNU/Linux, dovrebbe trattarsi della directory /usr/include/); nel secondo si fa riferimento a una posizione precisa, che richiede l'indicazione di un percorso se non si tratta della stessa posizione in cui si trova il sorgente in questione. *1*

Un file incorporato attraverso la direttiva #include, puÐ a sua volta includerne altri, e questa possibilitÞ va considerata per evitare di includere piÛ volte lo stesso file.

130.1.2 Direttiva #define

#define <macro> [<sequenza-di-caratteri>]

La direttiva #define permette di definire dei nomi, in questo caso si parla di macro (definite anche «costanti simboliche» o «costanti manifeste»), che, quando utilizzate nel sorgente, vengono sostituiti automaticamente con la sequenza che appare dopo la definizione. Per esempio,

#define SALUTO ciao come stai

farÞ in modo che il preprocessore sostituisca tutte le occorrenze di SALUTO con ciao come stai. õ molto importante comprendere questo particolare: tutto ciÐ che appare dopo il nome della macro sarÞ utilizzato nella sostituzione. Per esempio,

#define SALUTO "ciao come stai"

Õ diverso dal caso precedente, perchÈ ci sono in piÛ gli apici doppi. Questa volta, la macro SALUTO potrebbe essere utilizzata in un'istruzione come quella seguente,

printf( SALUTO );

mentre non sarebbe stato possibile quando la sostituzione era stata definita senza apici.

Visto questo, si puÐ osservare che questa direttiva puÐ essere utilizzata in modo piÛ complesso, facendo anche riferimento ad altre macro giÞ definite.

#define UNO 1
#define DUE UNO+UNO
#define TRE DUE+UNO

In presenza di una situazione come questa, utilizzando la macro TRE, si ottiene prima la sostituzione con DUE+UNO, quindi con UNO+UNO+1, e infine con 1+1+1 (dopo, tocca al compilatore).

L'utilizzo tipico delle macro Õ quello con cui si definiscono le dimensioni di qualcosa, per esempio gli array, e la corrispondenza reale di valori determinati che dipendono dalla piattaforma.

Per convenzione, i nomi utilizzati per le macro sono espressi solo con lettere maiuscole.

Come si vedrÞ meglio in seguito, Õ sensato anche dichiarare una macro senza alcuna corrispondenza. CiÐ puÐ servire per le direttive #ifdef e #ifndef.

130.1.3 Direttiva #define con argomento

#define <macro>(<argomento>) <sequenza-di-caratteri>

La direttiva #define puÐ essere usata in modo simile a una funzione, per definire delle sostituzioni che includono in qualche modo un argomento. Seguendo l'esempio seguente, l'istruzione i=DOPPIO(i) si traduce in i=(i)+(i).

#define DOPPIO(a)	(a)+(a)
...
...
i = DOPPIO(i);
...

Si osservi il fatto che, nella definizione, la stringa di sostituzione Õ stata composta utilizzando le parentesi. Questo permette di evitare problemi successivamente, nelle precedenze di valutazione delle espressioni.

130.1.4 Direttive #if, #else, #elif e #endif

#if <espressione>
	<espressione>
endif

Le direttive #if, #else, #elif e #endif, permettono di delimitare una porzione di codice che debba essere utilizzato o ignorato in relazione a una certa espressione che puÐ essere calcolata solo attraverso definizioni precedenti.

#define DIM_MAX 1000
...
...
main() {
...
#if DIM_MAX>100
    printf("Dimensione enorme.");
    ...
#else
    printf("Dimensione normale.");
    ...
#endif
...
}

L'esempio mostra in che modo si possa definire questa espressione, confrontando la macro DIM_MAX con il valore 100. Essendo stata dichiarata per tradursi in 1000, il confronto Õ equivalente a 1000>100 che risulta vero, pertanto il compilatore include solo le istruzioni relative.

In particolare, l'istruzione #elif, come si puÐ intuire, serve per costruire una catena di alternative else-if.

Gli operatori di confronto che si possono utilizzare per le espressioni logiche sono i soliti, in particolare, Õ bene ricordare che per valutare l'uguaglianza si usa l'operatore ==.

#define NAZIONE ita
...
...
main() {
#if NAZIONE==ita
    char valuta[] = "LIT";
    ...
#elsif NAZIONE==usa
    char valuta[] = "USD";
    ...
#endif
...
}

Queste direttive condizionali possono essere annidate, e inoltre possono contenere anche altri tipi di direttiva del preprocessore.

130.1.5 Direttive #ifdef e #ifndef

Le direttive #ifdef e #ifndef si aggiungono a quelle descritte nella sezione precedente, e servono per definire l'inclusione o l'esclusione di codice in base all'esistenza o meno di una macro.

#define DEBUG
...
main() {
...
#ifdef DEBUG
    printf( "Punto di controllo n. 1\n");
    ...
#endif
...
}

L'esempio mostra il caso in cui sia dichiarata una macro DEBUG (che non si traduce in alcunchÈ) e in base alla sua esistenza viene incluso il codice che mostra un messaggio particolare.

#define OK
...
main() {
#ifndef OK
    printf( "Punto di controllo n. 1\n");
    ...
#endif
...
}

L'esempio appena mostrato Õ analogo a quello precedente, con la differenza che la direttiva #ifndef permette la compilazione delle istruzioni che controlla solo se la macro indicata non Õ stata dichiarata.

L'uso delle direttive #else e #endif avviene nel modo giÞ visto per la direttiva #if.

130.1.6 Direttiva #undef

#undef <macro>

La direttiva #undef permette di eliminare una macro a un certo punto del sorgente.

#define NAZIONE ita
...
/* In questa posizione, NAZIONE risulta definita */
...
#undef NAZIONE
...
/* In questa posizione, NAZIONE non Õ definita */
...

130.2 Macro predefinite

Il compilatore C ANSI prevede alcune macro predefinite. Il loro scopo Õ quello di annotare informazioni legate alla compilazione nel file eseguibile finale (evidentemente a fini diagnostici).

130.2.1 File sorgente

Il programma puÐ accedere all'informazione sul nome del file sorgente e della riga originale. Questi dati sono contenuti, rispettivamente, nelle macro __FILE__ e __LINE__. Questi dati possono essere alterati nel sorgente, utilizzando la direttiva #line.

#line <numero-riga> "<nome-file>"

130.2.2 Data di compilazione

La data e l'ora della compilazione sono accessibili attraverso le macro __DATE__ e __TIME__. Il formato della prima macro Õ la consueta stringa «mese/giorno/anno» e quello della seconda Õ «ore:minuti:secondi».

130.2.3 C standard

Se il compilatore C che si utilizza Õ «standard», allora la macro __STDC__ corrisponde al valore 1. Qualunque altro valore indica che non si tratta di un compilatore standard.

---------------------------

Appunti Linux 1999.09.21 --- Copyright © 1997-1999 Daniele Giacomini --  daniele @ pluto.linux.it


1.) Quando si indica un file da includere, delimitandolo con gli apici doppi e senza indicare alcun percorso, se non si trova il file nella directory corrente, il file viene cercato nella directory predefinita, come se fosse stato indicato tra le parentesi angolari.


[inizio] [indice generale] [precedente] [successivo] [indice analitico] [contributi]