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 ReportTranscript 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011
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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime 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
jMULT_BY_TWO(5);
j10;
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(jMAX; j>0; j)
for(j100; 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 aa;
}
…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
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) aa
Se si passa alla macro un’espressione aritmetica…
j 2SQUARE(34);
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 runtime prevedono un insieme di file header
che occorre includere per poter richiamare le relative funzioni
28
Anno accademico 2010-2011