Anno accademico Il preprocessore del linguaggio C
Anno accademico Sommario Il preprocessoreIl preprocessore La sostituzione di macro La sostituzione di macro Le compilazioni condizionali Le compilazioni condizionali Linclusione di file Linclusione di file
Anno accademico preprocessoreIl 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 Elaborazione di macro Inclusione di file sorgente Inclusione di file sorgente Compilazione condizionale Compilazione condizionale, che consente di compilare porzio- ni distinte di codice sorgente in dipendenza del valore di unespressione aritmetica diesisTutte 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 Introduzione 1
Anno accademico Le direttive del preprocessore possono apparire ovunque nel codice sorgente (prima, dopo, o inframmezzate a istruzioni C) macroUna definizione di macro termina con un newline invece che con un punto e virgola backslash\Per suddividere una definizione di macro su più linee occorre dunque inserire un backslash, \, immediatamente prima del newline Esempio:Esempio: define LONG_MACRO Questa è una macro molto lunga\ define LONG_MACRO Questa è una macro molto lunga\ che si estende su due linee Introduzione 2
Anno accademico macro corpo della macroPer 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 corpo della macro espansione di macroQuando 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 Lutilizzo più comune delle macro consiste nella definizione di costanti numeriche: luso diretto di costanti nel codice costituisce una pratica di programmazione scadente, perché il programma diventa difficile da (leggere e) manutenere La sostituzione di macro 1
Anno accademico Oltre alle macro che definiscono costanti, esiste unulteriore forma di macro, simile ad una funzione C, che accetta argomenti che possono essere utilizzati nel corpo della macro La sintassi è: Esempio:Esempio: define MULT_BY_TWO(a) ((a) (a)) define MULT_BY_TWO(a) ((a) (a)) ) Argomento di macro define Corpo di macro, ( Nome di macro Sintassi di una macro di tipo funzione La sostituzione di macro 2
Anno accademico MULT_BY_TO MULT_BY_TO può essere utilizzata allinterno del programma, come una funzione: le prestazioni migliorano perché la somma costa meno della moltiplicazione a Il parametro attuale 5 viene sostituito al parametro formale a, in ogni sua occorrenza allinterno del corpo della macro a Le parentesi che delimitano a ed il corpo della macro sono necessarie per assicurare che il parametro venga istanziato correttamente allatto dellespansione 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 j 10; j MULT_BY_TWO(5); La sostituzione di macro 3
Anno accademico Le macro vengono normalmente eseguite più velocemente delle funzioni, perché non è necessario il salvataggio degli argomenti sullo stack Esempio:Esempio: Trasformazione da maiuscole a minuscole, nel caso di codifica ASCII La conversione di funzioni in macro comporta effetti significativi sui tempi di esecuzione del programma quando la frequenza di attivazione della funzione è elevata define TO_LOWER(c) ((c) (a A)) define TO_LOWER(c) ((c) (a A)) La sostituzione di macro 4
Anno accademico ;Lintroduzione di un ; al termine di una definizione di macro è un errore molto diffuso e molto pericoloso Esempio:Esempio: Il punto e virgola diviene parte integrante della stringa da espandere, per cui Lerrore non viene segnalato dal compilatore, che interpreta il secondo punto e virgola come unistruzione vuota Viceversa, produce un errore lespansione di… define size 10; define size 10; x 10;; x size; int array[size]; La linea a cui viene fatto riferimento nel messaggio di errore è corretta! Errori comuni 1
Anno accademico Lerrore più pericoloso si verifica quando, a seguito dellespansione della macro, listruzione risultante è sintatticamente corretta, ma ha una semantica non corrispondente alle attese Esempio:Esempio: (var 1) while whilevar Il ; che segue (var 1) viene interpretato come unistruzione 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 unopzione per eseguire solo il preprocessore, così da esaminare il codice risultante dopo lespansione di tutte le macro while (var 1); foo(); foo(); define GOOD_CONDITION (var 1); define GOOD_CONDITION (var 1); … … … while GOOD_CONDITION foo(); foo(); Errori comuni 2
Anno accademico Altro errore molto diffuso è luso delloperatore di assegnamento nella definizione di una macro, in analogia allinizializzazione di variabili Lerrore può condurre ad anomalie nel codice di difficile individuazione Esempio:Esempio: produrrebbe… Lassegnamento diviene unespressione relazionale sintatticamente corretta, che il compilatore non evidenzia errore difficile da rilevare define MAX 100 define MAX 100 for(j 100; j>0; j ) for(j MAX; j>0; j ) Errori comuni 3
Anno accademico La parentesi sinistra che racchiude il parametro (/i) deve seguire immediatamente il nome della macro, senza la presenza di spazi bianchi: lerrore viene normalmente segnalato in compilazione Esempio:Esempio: produrrebbe… Se invece fosse stato inserito uno spazio bianco, lespres- sione viene espansa in a f perfettamente lecita se a è un nome di variabile ed f una funzione define NEG_A_PLUS_F(a) ( (a) f) define NEG_A_PLUS_F(a) ( (a) f) j (x) f; j NEG_A_PLUS_F(x); j (a) (a) f(x); Errori comuni 4
Anno accademico Esempio:Esempio: 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 sqrtLespansione della macro sqrt produrrebbe… Nota:Nota: luso di un nome di macro, allinterno della propria definizione, ha senso solo se esiste una funzione con lo stesso nome define sqrt(x) ((x<0) ? sqrt( x):sqrt(x)) define sqrt(x) ((x<0) ? sqrt( x):sqrt(x)) y ((5<0) ? sqrt( 5):sqrt(5)); y sqrt(5); Luso del nome di macro nella definizione
Anno accademico Dal punto di vista operativo… …lutilizzo 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 (nellesempio), 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 dellesistenza del prototipo MULT_BY_TOa MULT_BY_TO può ricevere un parametro a di tipo qualsiasi int mult_by_to(a) int a; { return a a; return a a;} define MULT_BY_TWO(a) ((a) (a)) define MULT_BY_TWO(a) ((a) (a)) Assenza di controllo per gli argomenti di macro 1
Anno accademico Lassenza di controlli di tipo sugli argomenti delle macro aggiunge flessibilità alla programmazione Esempio:Esempio: ab 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 define MIN(a,b) ((a)<(b) ? (a) : (b)) define MIN(a,b) ((a)<(b) ? (a) : (b)) Assenza di controllo per gli argomenti di macro 2
Anno accademico Esempio:Esempio: bcb se b < c, b viene incrementato due volte Per non incorrere in comportamenti indesiderati, occorre non utilizzare, nelle chiamate di macro, operatori che implicano effetti collaterali (operatori di incremento, decremento, assegnamento, etc.) a ((b )<c ? (b ):(c)); a MIN(b,c); Gli effetti collaterali negli argomenti di macro
Anno accademico bindingLuso di espressioni in cui le parentesi non siano utilizzate correttamente, come argomenti di macro, può produrre compor- tamenti indesiderati, a causa della precedenza degli operatori e del binding Esempio:Esempio: Se si passa alla macro unespressione aritmetica… j …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 define SQUARE(a) a a define SQUARE(a) a a j ; j 2 SQUARE(3 4); Il binding degli argomenti
Anno accademico undefLa 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 luso della direttiva apposita, a meno che le definizioni coincidano La cancellazione di una definizione di macro
Anno accademico Sia macro che funzioni consentono di rappresentare con un singolo nome (alias) un insieme di operazioniSia macro che funzioni consentono di rappresentare con un singolo nome (alias) un insieme di operazioni VantaggiVantaggi 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) Macro vs Funzioni 1
Anno accademico SvantaggiSvantaggi Gli argomenti di macro vengono valutati ogni volta che compaiono allinterno 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 debugging 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 Macro vs Funzioni 2
Anno accademico if else elif endifIl preprocessore consente di selezionare le porzioni di codice che devono essere compilate, attraverso le di- rettive if, else, elif, endif Esempio:Esempio: Codice sorgente C Espressione condizionale endif if Espressione condizionale elif Codice sorgente C else La sintassi delle direttive di compilazione condizionale if x 1 if x 1 undef x undef x define x 0 define x 0 elif x 2 elif x 2 undef x undef x define x 3 define x 3 else else define y 4 define y 4 endif endif Le compilazioni condizionali 1
Anno accademico if elifLespressione condizionale contenuta in una direttiva if o elif deve essere una costante, che non deve neces- sariamente essere racchiusa tra parentesi (sono opzionali) elif else ifLa direttiva elif è equivalente al costrutto else if del linguaggio C elif else endifI blocchi di istruzioni dipendenti da una direttiva condizionale di preprocessore non sono racchiusi tra parentesi graffe, ma sono delimitati da unistruzione elif, else, o endif if elif elseOgni blocco if può contenere un numero qualsiasi di blocchi elif, ma un solo blocco else, che deve essere lultimo if endifOgni blocco if deve essere terminato da una direttiva endif Le compilazioni condizionali 2
Anno accademico Inoltre… Le macro che compaiono in unespressione condizionale vengono espanse prima della valutazione dellespressione if 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 debuggingLe compilazioni condizionali sono particolarmente utili nella fase di debugging, durante lo sviluppo di un programma, per attivare o disattivare porzioni di codice 23 Le compilazioni condizionali 3
Anno accademico Le direttive if e endif controllano la compilazione delle istruzioni C racchiuse nel blocco condizionale, non la loro esecuzioneLe direttive if e endif controllano la compilazione delle istruzioni C racchiuse nel blocco condizionale, non la loro esecuzione 24 if DEBUG if DEBUG if (exp_debug) if (exp_debug) { … … … … … … } endif endif Le compilazioni condizionali 4
Anno accademico if elifLe direttive if e elif consentono la compilazione condizionale, in dipendenza del valore di unespressione aritmetica ifdef ifndef endifSi può compilare in modo condizionale anche in dipendenza dellesistenza o meno di una macro, mediante le direttive ifdef, ifndef e endif TEST printf() Se la macro TEST è definita, viene compilata la prima printf(), altrimenti viene compilata la seconda ifdef TEST ifdef TEST printf(Questo è un test. \n); printf(Questo è un test. \n); else else printf(Questo non è un test. \n); printf(Questo non è un test. \n); endif endif Il controllo dellesistenza di una macro 1
Anno accademico if ifdef ifndefNella maggior parte dei casi è possibile utilizzare if invece di ifdef e ifndef, poiché un nome di macro viene espanso a zero se non è definito ifdef ifndefLeccezione che richiede luso di ifdef e ifndef è costituita dalle macro definite come zero Esempio: FALSEEsempio: Si supponga di definire la macro FALSE come zero… ifndef FALSE ifndef FALSE define FALSE 0 define FALSE 0 elif FALSE elif FALSE undef FALSE undef FALSE define FALSE 0 define FALSE 0 endif endif FALSE FALSE viene comunque ridefinita se è stata definita come zero, mai altrimenti if !FALSE if !FALSE define FALSE 0 define FALSE 0 endif endif Soluzione Il controllo dellesistenza di una macro 2
Anno accademico includeLa direttiva include può presentarsi in uno dei due formati: UNIX LINUX /usr/include …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 include file headerIl comando include consente di includere file di defini- zione comuni, i file header, che possono essere condivisi da più file sorgente include nome_file include nome_file include include Linclusione di file 1
Anno accademico hI file header sono caratterizzati dallestensione.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 UNIXLINUXMolti sistemi operativi (UNIX, LINUX) forniscono file header contenenti la definizione di strutture interne del SO Anche le librerie di run time prevedono un insieme di file header che occorre includere per poter richiamare le relative funzioni Linclusione di file 2