Il preprocessore del linguaggio C Anno accademico 2010-2011 Sommario • Il preprocessore  La sostituzione di macro  Le compilazioni condizionali  L’inclusione di file Anno accademico.

Download Report

Transcript Il preprocessore del linguaggio C Anno accademico 2010-2011 Sommario • Il preprocessore  La sostituzione di macro  Le compilazioni condizionali  L’inclusione di file Anno accademico.

Slide 1

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 2

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 3

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 4

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 5

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 6

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 7

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 8

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 9

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 10

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 11

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 12

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 13

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 14

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 15

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 16

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 17

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 18

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 19

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 20

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 21

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 22

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 23

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 24

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 25

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 26

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 27

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011


Slide 28

Il preprocessore del linguaggio C

1
Anno accademico 2010-2011

Sommario
• Il preprocessore
 La sostituzione di macro
 Le compilazioni condizionali
 L’inclusione di file

2
Anno accademico 2010-2011

Introduzione  1
• Il preprocessore del linguaggio C è un programma a sé
stante, che viene eseguito prima del compilatore, con propri
lessico e sintassi, orientati alle linee
• Le principali funzioni offerte dal preprocessore sono:

 Elaborazione di macro
 Inclusione di file sorgente
 Compilazione condizionale, che consente di compilare porzio-

ni distinte di codice sorgente in dipendenza del valore di
un’espressione aritmetica

• Tutte le direttive per il preprocessore iniziano con il carattere
diesis,  (il cancelletto), che deve essere il primo carattere
della linea a meno di spazi bianchi
3
Anno accademico 2010-2011

Introduzione  2
• Le direttive del preprocessore possono apparire ovunque nel
codice sorgente (prima, dopo, o inframmezzate a istruzioni C)
• Una definizione di macro termina con un newline invece che
con un punto e virgola
• Per suddividere una definizione di macro su più linee occorre
dunque inserire un backslash, \, immediatamente prima del
newline
• Esempio:
define LONG_MACRO “Questa è una macro molto lunga\
che si estende su due linee”

4
Anno accademico 2010-2011

La sostituzione di macro  1
• Per macro si intende un nome a cui è associata una stringa testuale,
detta corpo della macro
• Per convenzione, i nomi di macro dovrebbero essere costituiti da
sole lettere maiuscole e dovrebbero essere significativi del
contenuto della macro
• Per lo standard ANSI, due nomi di macro sono distinti se
differiscono in almeno uno dei primi 31 caratteri
• Quando un nome di macro viene invocato nel codice al di fuori del
punto di definizione, viene sostituito dal corpo della macro: si ha
una espansione di macro
• L’utilizzo più comune delle macro consiste nella definizione di
costanti numeriche: l’uso diretto di costanti nel codice costituisce
una pratica di programmazione scadente, perché il programma
diventa difficile da (leggere e) manutenere
Anno accademico 2010-2011

5

La sostituzione di macro  2
• Oltre alle macro che definiscono costanti, esiste un’ulteriore
forma di macro, simile ad una funzione C, che accetta
argomenti che possono essere utilizzati nel corpo della
macro
,
• La sintassi è:


define

)

• Esempio:

Corpo di macro

Nome di macro

(

Argomento di
macro

Sintassi di una macro di tipo funzione

define MULT_BY_TWO(a) ((a)(a))
6

Anno accademico 2010-2011

La sostituzione di macro  3
• MULT_BY_TO può essere utilizzata all’interno del programma, come
una funzione: le prestazioni migliorano perché la somma “costa”
meno della moltiplicazione

jMULT_BY_TWO(5);

j10;

Il parametro attuale 5 viene sostituito al parametro formale a, in ogni
sua occorrenza all’interno del corpo della macro
 Le parentesi che delimitano a ed il corpo della macro sono necessarie
per assicurare che il parametro venga istanziato correttamente all’atto
dell’espansione della macro


• I parametri di una macro non sono variabili: non è definito il loro
tipo, né viene loro assegnata memoria  non sono in conflitto con
variabili esistenti con lo stesso nome

7
Anno accademico 2010-2011

La sostituzione di macro  4
• Le macro vengono normalmente eseguite più velocemente
delle funzioni, perché non è necessario il salvataggio degli
argomenti sullo stack
• Esempio: Trasformazione da maiuscole a minuscole, nel caso
di codifica ASCII

define TO_LOWER(c) ((c)(‘a’‘A’))
• La conversione di funzioni in macro comporta effetti
significativi sui tempi di esecuzione del programma quando la
frequenza di attivazione della funzione è elevata
8
Anno accademico 2010-2011

Errori comuni  1
• L’introduzione di un ; al termine di una definizione di macro è un
errore molto diffuso e molto pericoloso
• Esempio:
define size 10;
Il punto e virgola diviene parte integrante della stringa da
espandere, per cui
x  size;

x  10;;

L’errore non viene segnalato dal compilatore, che interpreta il
secondo punto e virgola come un’istruzione vuota
• Viceversa, produce un errore l’espansione di…
int array[size];

La linea a cui viene fatto riferimento
nel messaggio di errore è corretta!
9

Anno accademico 2010-2011

Errori comuni  2
• L’errore più pericoloso si verifica quando, a seguito dell’espansione
della macro, l’istruzione risultante è sintatticamente corretta, ma ha
una semantica non corrispondente alle attese
• Esempio:
define GOOD_CONDITION (var  1);
… … …
while GOOD_CONDITION
foo();

while (var  1);
foo();

Il “;” che segue (var  1) viene interpretato come un’istruzione
vuota, che costituisce il corpo del ciclo while  la chiamata alla
funzione non fa parte del corpo del while e se var coincide con 1 si
produce un ciclo infinito
• I compilatori prevedono un’opzione per eseguire solo il preprocessore,
così da esaminare il codice risultante dopo l’espansione di tutte le
macro
10
Anno accademico 2010-2011

Errori comuni  3
• Altro errore molto diffuso è l’uso dell’operatore di assegnamento
nella definizione di una macro, in analogia all’inizializzazione di
variabili
• L’errore può condurre ad anomalie nel codice di difficile
individuazione
• Esempio:
define MAX  100
produrrebbe…
for(jMAX; j>0; j)

for(j100; j>0; j)

L’assegnamento diviene un’espressione relazionale sintatticamente
corretta, che il compilatore non evidenzia  errore difficile da
rilevare
11
Anno accademico 2010-2011

Errori comuni  4
• La parentesi sinistra che racchiude il parametro (/i) deve
seguire immediatamente il nome della macro, senza la
presenza di spazi bianchi: l’errore viene “normalmente”
segnalato in compilazione
• Esempio: define NEG_A_PLUS_F(a) ((a)f)
produrrebbe…
j  NEG_A_PLUS_F(x);

j  (x)f;

Se invece fosse stato inserito uno spazio bianco, l’espressione viene espansa in
j  (a)(a)f(x);

perfettamente lecita se a è un nome di variabile ed f una
funzione
Anno accademico 2010-2011

12

L’uso del nome di macro nella definizione
• Esempio:
define sqrt(x) ((x<0) ? sqrt(x):sqrt(x))
• Lo standard ANSI stabilisce che, se un nome di macro
compare nella propria definizione, allora non viene espanso:
si evita il problema delle espansioni infinite
• L’espansione della macro sqrt produrrebbe…
y  sqrt(5);

y  ((5<0) ? sqrt(5):sqrt(5));

• Nota: l’uso di un nome di macro, all’interno della propria
definizione, ha senso solo se esiste una funzione con lo stesso
nome
13
Anno accademico 2010-2011

Assenza di controllo per
gli argomenti di macro  1
• Dal punto di vista operativo…
define MULT_BY_TWO(a) ((a)(a))

int mult_by_to(a)
int a;
{
return aa;
}

…l’utilizzo di una macro o di una funzione non produce un
risultato equivalente; infatti:

 Sul parametro della macro non viene eseguito alcun controllo di

tipo; la funzione (nell’esempio), invece, presuppone un
argomento intero e restituisce un valore intero
 Se alla funzione viene passata una costante reale, il compilatore
può comportarsi diversamente, in dipendenza dell’esistenza del
prototipo
 MULT_BY_TO può ricevere un parametro a di tipo qualsiasi
Anno accademico 2010-2011

14

Assenza di controllo per
gli argomenti di macro  2
• L’assenza di controlli di tipo sugli argomenti delle macro
aggiunge flessibilità alla programmazione
• Esempio: define MIN(a,b) ((a)<(b) ? (a) : (b))


funziona con a e b sia interi che reali
• Fra funzioni e macro esiste anche una sostanziale differenza sul
controllo del numero dei parametri, tra definizione e
invocazione:

 Nelle funzioni, il compilatore C effettua il controllo solo se esiste un

prototipo; in caso contrario, la chiamata di funzione viene
compilata correttamente, con impredicibilità del comportamento in
fase di esecuzione
 Per le macro, si ha sempre una segnalazione di errore in fase di
compilazione
15

Anno accademico 2010-2011

Gli effetti collaterali
negli argomenti di macro
• Esempio:
a  MIN(b,c);

a  ((b)
se b• Per non incorrere in comportamenti indesiderati, occorre non
utilizzare, nelle chiamate di macro, operatori che implicano
effetti collaterali (operatori di incremento, decremento,
assegnamento, etc.)

16
Anno accademico 2010-2011

Il binding degli argomenti
• L’uso di espressioni in cui le parentesi non siano utilizzate
correttamente, come argomenti di macro, può produrre comportamenti indesiderati, a causa della precedenza degli operatori e del
binding
• Esempio:
define SQUARE(a) aa
Se si passa alla macro un’espressione aritmetica…
j  2SQUARE(34);

j  2  3  4  3  4;

…che assegna il valore 22 a j, piuttosto che il valore corretto 98
 Il corpo e gli argomenti di una macro devono essere sempre
racchiusi fra parentesi
17
Anno accademico 2010-2011

La cancellazione di una definizione
di macro
• La definizione di una macro mantiene la sua validità fino al
termine del file sorgente, o fino a quando non viene
esplicitamente “cancellata”, per mezzo della direttiva undef
• Non è possibile ridefinire una macro senza prima averla
cancellata con l’uso della direttiva apposita, a meno che le
definizioni coincidano

18
Anno accademico 2010-2011

Macro vs Funzioni  1
• Sia macro che funzioni consentono di rappresentare con un
singolo nome (alias) un insieme di operazioni
• Vantaggi
 Le macro sono più veloci, perché non richiedono le operazioni

connesse con le chiamate di funzione (salvataggio del contesto)

 Il numero degli argomenti delle macro è sempre soggetto a

controllo da parte del compilatore

 Non è imposto alcun vincolo sul tipo degli argomenti (la stessa

macro può essere utilizzata su più tipi di dati)

19
Anno accademico 2010-2011

Macro vs Funzioni  2
• Svantaggi
 Gli

argomenti di macro vengono valutati ogni volta che
compaiono all’interno del corpo della macro  possibili effetti
collaterali indesiderati

 Il corpo delle funzioni è compilato una sola volta: molteplici

chiamate alla stessa funzione usufruiscono dello stesso codice
eseguibile; le macro vengono espanse ad ogni occorrenza

 Nelle macro non vi è controllo di tipo sugli argomenti; le funzioni

definite con prototipi controllano sia il numero che il tipo degli
argomenti

 La fase di debugging per programmi contenenti macro è più

complicata: il codice sorgente è sottoposto a due fasi di
traduzione  il codice oggetto è più “distante” dal sorgente
20

Anno accademico 2010-2011

Le compilazioni condizionali  1
• Il preprocessore consente
di selezionare le porzioni di
codice che devono essere
compilate, attraverso le direttive if, else, elif,
endif
• Esempio: if x  1
undef x
define x 0
elif x  2
undef x
define x 3
else
define y 4
endif
Anno accademico 2010-2011

Espressione
condizionale

if



Codice
sorgente C



elif



else

Codice
sorgente C



Espressione
condizionale

La sintassi delle direttive di
compilazione condizionale

endif
21

Le compilazioni condizionali  2
• L’espressione condizionale contenuta in una direttiva if o
elif deve essere una costante, che non deve necessariamente essere racchiusa tra parentesi (sono opzionali)
• La direttiva elif è equivalente al costrutto else if del
linguaggio C
• I blocchi di istruzioni dipendenti da una direttiva condizionale
di preprocessore non sono racchiusi tra parentesi graffe, ma
sono delimitati da un’istruzione elif, else, o endif
• Ogni blocco if può contenere un numero qualsiasi di
blocchi elif, ma un solo blocco else, che deve essere
l’ultimo
• Ogni blocco if deve essere terminato da una direttiva
endif
Anno accademico 2010-2011

22

Le compilazioni condizionali  3
• Inoltre…
 Le

macro che compaiono in un’espressione condizionale
vengono espanse prima della valutazione dell’espressione
 Le direttive condizionali di preprocessore possono essere
innestate (come gli if nel linguaggio C)
 Le istruzioni comprese in blocchi condizionali possono essere
anche istruzioni del linguaggio C

• Le compilazioni condizionali sono particolarmente utili nella
fase di debugging, durante lo sviluppo di un programma, per
attivare o disattivare porzioni di codice

23
Anno accademico 2010-2011

Le compilazioni condizionali  4
• Le direttive if e endif controllano la compilazione delle
istruzioni C racchiuse nel blocco condizionale, non la loro
esecuzione
if

DEBUG
if (exp_debug)
{
… … …
}
endif

24
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  1
• Le direttive if e elif consentono la compilazione
condizionale, in dipendenza del valore di un’espressione
aritmetica
• Si può compilare in modo condizionale anche in dipendenza
dell’esistenza o meno di una macro, mediante le direttive
ifdef, ifndef e endif
ifdef TEST
printf(“Questo è un test. \n”);
else
printf(“Questo non è un test. \n”);
endif

Se la macro TEST è definita, viene compilata la prima
printf(), altrimenti viene compilata la seconda
25
Anno accademico 2010-2011

Il controllo dell’esistenza
di una macro  2
• Nella maggior parte dei casi è possibile utilizzare if invece di
ifdef e ifndef, poiché un nome di macro viene espanso a
zero se non è definito
• L’eccezione che richiede l’uso di ifdef e ifndef è costituita
dalle macro definite come zero
• Esempio: Si supponga di definire la macro FALSE come zero…
if !FALSE


define FALSE 0

endif

Soluzione

Anno accademico 2010-2011

FALSE viene comunque ridefinita
se è stata definita come zero, mai
altrimenti
ifndef FALSE

define FALSE 0
elif FALSE

undef FALSE

define FALSE 0
endif

26

L’inclusione di file  1
• La direttiva include può presentarsi in uno dei due
formati:
include

include “nome_file”

…nel primo caso, il preprocessore cerca il file in un insieme di directory
dipendenti dal sistema (ad esempio, in UNIX come in LINUX, i file
standard di include sono contenuti in /usr/include)
 …nel secondo caso, il preprocessore cerca il file secondo le usuali
regole di ricerca per lo specifico sistema operativo (tipicamente la
ricerca viene effettuata nella directory corrente); se la ricerca fallisce,
si procede come nel primo caso


• Il comando include consente di includere file di definizione comuni, i file header, che possono essere condivisi da
più file sorgente

27
Anno accademico 2010-2011

L’inclusione di file  2
• I file header sono caratterizzati dall’estensione .h e contengono i
prototipi di funzione, le definizioni delle strutture dati, delle macro e
dei dati globali, necessari alla comunicazione fra moduli
• Scopo dei file header è quello di sintetizzare in un unico file le
informazioni comuni, invece di replicarle in ogni file sorgente
 si semplifica la programmazione e la manutenzione del codice

• Molti sistemi operativi (UNIX, LINUX) forniscono file header
contenenti la definizione di strutture interne del SO
• Anche le librerie di runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011