Sei sulla pagina 1di 6

2

Funzionalità
 Modifica il codice C prima che venga eseguita
la traduzione vera a propria
Il preprocessore C  Le direttive al preprocessore riguardano:
 inclusione di file (#include)
 definizione di simboli (#define)
 sostituzione di simboli (#define)
Ver. 2.4  compilazione condizionale (#if)
 macroistruzioni con parametri (#define)
 Non essendo istruzioni C non richiedono
il ‘;’ finale

© 2010 - Claudio Fornaro - Corso di programmazione in C

3 4

Inclusione di file Inclusione di file


 La riga con #include viene sostituita dal  I file inclusi possono a loro volta contenere
contenuto testuale del file indicato altre direttive #include
#include <stdio.h>  La direttiva #include viene in genere
 Il nome del file può essere completo di collocata in testa al file sorgente C, prima
percorso della prima funzione
 Ha due forme:  Generalmente, i file inclusi non contengono
 #include <file.h> codice eseguibile, ma solo dichiarazioni (es.
Il file viene cercato nelle directory del compilatore prototipi e variabili extern) e altre direttive
 #include "file.h"
Il file viene cercato prima nella directory dove si
trova il file C e poi, se non trovato, nelle directory
del compilatore
5 6

Definizione di simboli Sostituzione di simboli


 #define nome  Sono dette anche macro o macroistruzioni
definisce il simbolo denominato nome  #define nome testo_sostitutivo
#define DEBUG sostituisce i caratteri di nome con i caratteri di
 I simboli vengono utilizzati dalle altre direttive testo_sostitutivo in ogni punto del programma
del preprocessore (ad es. si può verificare se dove nome appare come identificatore (ossia
un simbolo è stato definito o no con #if) sembra una variabile)
 Lo scope di nome si estende dalla riga con la #define MAX 100
definizione fino alla fine di quel file sorgente e ...
non tiene conto dei blocchi di codice for (i=0; i<MAX; i++)
 nome ha la stessa sintassi di un identificatore  La sostituzione (detta anche “espansione”)
(nome di variabile), non può contenere spazi e avviene prima della compilazione vera e
viene per convenzione scritto in maiuscolo propria, quindi il compilatore non troverà la
 #undef nome riga di codice precedente, ma la seguente:
annulla una #define precedente for (i=0; i<100; i++)

7 8

Sostituzione di simboli Sostituzione di simboli


 nome non può essere definito più volte  L’ordine di elencazione delle #define non è
 nome ha la sintassi degli identificatori, viene rilevante: dopo una sostituzione su una riga,
per convenzione scritto tutto maiuscolo se questa viene considerata nuovamente per
testo_sostitutivo è una quantità costante (ossia verificare se quanto ottenuto può essere
non si tratta di una macro con argomenti ) sottoposto ad un’altra sostituzione
 testo_sostitutivo termina a fine riga:  #define C 3
 può contenere spazi
#define B C
 può utilizzare nomi di #define precedenti
#define A B
trasforma ogni A in B, ogni B in C e ogni C in
 se manca, si ha la semplice definizione di nome e
quindi tutte le occorrenze di nome sono eliminate 3, quindi tutte le A, le B e le C in 3
 può continuare su più righe purché ogni riga da  Se un nome è stato sostituito da un’espansione
continuare termini con il carattere ‘\’ (dal punto di e compare nuovamente per effetto di altre
vista logico si tratta di una sola lunga riga) espansioni, non viene sostituito nuovamente
9 10

Sostituzione di simboli Macro con argomenti


 Attenzione: essendo una semplice sostituzione  Sembra una chiamata di funzione con
di caratteri, si può incorrere in errori parametri, invece è un’espansione di macro:
 Esempio: il seguente ciclo non va fino a 202 esecuzione più veloce, programma più grande
#define MAX 100+1 #define max(A,B) ((A)>(B)?(A):(B))
...  I simboli A e B sono sostituiti dagli argomenti
for (i=0; i<MAX*2; i++) presenti nella “chiamata” della macro
In realtà va fino a 102 in quanto la sostituzione  La prima parte della #define non può avere
produce il seguente codice: spazi intermedi, nell’utilizzo possono esserci
for (i=0; i<100+1*2; i++)  Esempio
Per evitare il problema a priori, è possibile x = max(p+q, r+s); viene espansa in
indicare il valore tra parentesi nella define: x = ((p+q)>(r+s)?(p+q):(r+s));
#define MAX (100+1) Si noti che funziona per tutti i tipi di dati

11 12

Macro con argomenti Macro con argomenti


 Attenzione agli effetti collaterali:  In testo_sostitutivo il nome di un parametro
 max(i++,j++) viene sostituita da preceduto da un # viene sostituito
((i++)>(j++)?(i++):(j++)) dall’argomento racchiuso tra virgolette
e il valore più grande tra i e j viene incrementato #define eprint(expr) \
due volte printf(#expr "=%g\n", expr)
 Attenzione alle parentesi: la macro eprint(x/y) viene sostituita da:
 #define quadrato(x) (x)*(x) printf("x/y" "=%g\n", x/y)
chiamata come quadrato(z+1) viene e le due stringhe vicine vengono concatenate
correttamente sostituita da (z+1)*(z+1) dal compilatore in "x/y=%g\n"
 #define quadrato(x) x*x  L’operatore di preprocessore ## concatena
chiamata come quadrato(z+1) viene due argomenti rimuovendo gli spazi intermedi
erroneamente sostituita da z+1*z+1 #define concat(uno,due) uno ## due
concat(nome,6) viene sostituito da nome6
13 14

Macro composte Macro composte


 Il corpo della macro (testo_sostitutivo) può  Perché la macro composta restituisca un valore
contenere più istruzioni C come una funzione, se possibile si separano le
istruzioni mediante virgole (dà come valore
 #define swap(x,y) t=x; x=y; y=t; quello dell’espr. più a destra)
 La macro precedente viene chiamata come: #define maxswap(x,y) \
swap(a,b)  (t=x, x=y, y=t, x>y?x:y)
chiamata come: maxswap(a,b);
 Per chiamarla come fosse una funzione
 Se serve definire una variabile temporanea per
void, è sufficiente non indicare all’estrema la macro, si crea un blocco con una coppia di
destra nella definizione il punto e virgola parentesi graffe:
swap(a,b);  CON ‘;’ #define swap(x,y) \
{ int t; t=x; x=y; y=t; }
Questa macro deve essere chiamata senza il ‘;’
swap(a,b)

15 16

Macro composte Inclusione condizionale


 Per poter chiamare anche la macro precedente  Permette di include o escludere parte del
con il ‘;’ a fine istruzione così che sembri una codice dalla compilazione e dal preprocessing
stesso
funzione, si scrivono le istruzioni all’interno di
un ciclo do-while fittizio (sempre falso, non  #if espressione_1
istruzioni
lo ripete mai) e privo del ‘;’ finale: #elif espressione_2
#define swap(x,y) \ istruzioni
do { \ ...
int t; t=x; x=y; y=t; \ #else
}while (0) istruzioni
Questa macro deve essere chiamata con il ‘;’ #endif
finale:  Solo uno dei gruppi di istruzioni sarà elaborato
swap(a,b); dal preprocessore e poi compilato
17 18

Inclusione condizionale Inclusione condizionale


 Le espressioni devono essere costanti intere  Esempio
(non possono contenere sizeof(), cast o Per far compilare parti diverse a seconda del
costanti enum), sono considerate vere se !=0 sistema operativo, si può usare lo schema
seguente (il simbolo _WIN32 viene definito da
 L’espressione defined(nome) produce tutti i compilatori Win32):
1 se nome è stato definito (con #define), #ifdef _WIN32
0 altrimenti if (_oneexit(funz)==NULL)
 #ifdef nome equivale a: abort();
#if defined(nome) #else
atexit(funz);
e verifica che nome sia definito #endif
 #ifndef nome equivale a: Sono due funzioni quasi equivalenti, la prima
#if !defined(nome) esiste solo sui sistemi Win32, la seconda è
e verifica che nome non sia definito standard

19 20

Inclusione condizionale Inclusione condizionale


 Nel caso in cui un file incluso ne includa a sua  Per escludere dalla compilazione un grosso
volta altri, per evitare di includere più volte lo blocco di codice (anche con commenti):
#if 0
stesso file, si può usare lo schema seguente
codice da non eseguire
(quello che segue è il file hdr.h): #endif
#ifndef HDR
#define HDR  Per isolare istruzioni da usare solo per il
debug:
... contenuto di <hdr.h> #ifdef DEBUG
#endif printf("Valore di x: %d\n", x);
 Se venisse incluso una seconda volta, il #endif
simbolo HDR sarebbe già definito e il La #define DEBUG viene eliminata a
programma ultimato (spesso il simbolo DEBUG
contenuto non verrebbe nuovamente incluso
viene definito dal compilatore stesso se in
nella compilazione configurazione debug)
21 22

Macro predefinite Macro predefinite


 Sono simboli definiti dal preprocessore:  La direttiva #line può essere seguita da un
__DATE__ Data di compilazione del file sorgente nel numero intero per impostare il valore di
formato di asctime() (in <time.h>) __LINE__ della riga corrente del codice C, la
__FILE__ Nome del file corrente tra virgolette numerazione delle righe successive prosegue
__LINE__ Numero di linea della riga corrente nel file da quel valore
sorgente, può essere alterato da #line #line 100
__STDC__ Indica che il compilatore è completamente  La direttiva #line può inoltre impostare un
aderente allo standard ANSI e non
fornisce alcuna estensione nuovo nome di file
__TIME__ Ora di compilazione del file sorgente nella
#line 100 "file1.c"
forma hh:mm:ss.  Il valore di __LINE__ e il nome del file
__TIMESTAMP__ Data e ora di compilazione del file vengono usati nelle informazioni di
diagnostica fornite dal compilatore

23

Esercizi
1. Scrivere una macro swap(t,x,y) che
scambi il valore di due argomenti di tipo t.
2. Scrivere una macro printArray(v,n) che
visualizzi il contenuto del vettore v di
lunghezza n.
3. Scrivere una macro sumArray(v,n,sum)
che sommi gli n valori del vettore v e metta il
risultato in sum.