28.1 I file header
I file header (file testata) sono dei file che racchiudono informazioni necessarie al programma e vengono inclusi nel sorgente dal preprocessore. Il preprocessore e' un programma che fa parte del compilatore che effettua una elaborazione preliminare del sorgente. Il preprocessore (o precompilatore) modifica il sorgente seguendo alcune direttive scritte dal programmatore. Il file sorgente cosi' modificato viene successivamente elaborato dal compilatore vero e proprio. Le direttive del precompilatore sono evidenziate dal carattere '#' iniziale (il simbolo '#' viene chiamato pound negli USA, hash fuori degli USA e cancelletto in Italia. Etimologicamente parlando probabilmente il termine hash deriva da 'hatch' cioe' portellone, cancello, porta composta da sbarre incrociate cosi' come raffigurato dal simbolo stesso). Una direttiva importante che viene impartita al preprocessore e' la direttiva #include. Tale direttiva permette di includere i file header all'interno del sorgente del programma. I file header sono file di testo con estensione '.h' (da Header) e contengono le definizioni delle variabili, delle espressioni costanti e dei prototipi delle funzioni. Ad esempio, nel file header 'stdio.h' (STandarD Input/Output) sono contenuti le definizioni delle variabili, delle espressioni costanti ed i prototipi delle funzioni di Input e di Output della libreria standard del C. Esempi di funzioni I/O stantdard del C sono le funzioni printf(), getchar() e putchar(). Se il file stdio.h non venisse incluso all'interno del programma, il compilatore non riconoscerebbe le funzioni standard tipo printf() e genererebbe un errore di funzione non definita. In realta' generalmente le cose non stanno cosi' poiche' il file stdio.h se non incluso dal programmatore viene spesso incluso di default dal compilatore stesso. Il preprocessore leggendo la direttiva #include copia (o meglio lo 'include') il file dichiarato all'interno del sorgente del programma. Una volta elaborato dal preprocessore quindi, il file sorgente conterra' al posto della riga '#include 28.2 la direttiva #define e le macro
Un'altra direttiva molto usata e' #define per creare delle espressioni costanti. Una espressione costante permette di usare un nome significativo al posto di un valore costante come ad esempio 'ON' (acceso) al posto di 1 e 'OFF' (spento) al posto di 0. La sintassi della direttiva #define e': '#define nome espressione'. Il preprocessore quando incontra la direttiva #define sostituisce qualsiasi occorrenza identificata da 'nome' con l'espressione 'espressione'. E' possibile scrivere direttive #define su piu' righe usando il carattere '\' alla fine di ogni riga. Questa direttiva pero' puo' essere usata anche per creare delle macro. Ecco alcuni esempi di macro create utilizzando la direttiva #define:
l'ultima direttiva sostituisce qualsiasi occorrenza di max(a,b) con l'espressione ((a) > (b) ? (a) : (b)). Ad esempio la riga:
Nella definizione delle macro occorre prestare attenzione alle parentesi onde evitare spiacevoli effetti collaterali. Ad esempio la macro:
e' errata perche' quando viene incontrata un'espressione del tipo quad(x 1) viene espansa nellla forma: (x 1*x 1). Poiche' l'operatore * ha una precedenza maggiore dell'operatore , verrebbe eseguita per prima la moltiplicazione. Sostituendo x con un valore qualsiasi, ad esempio 3, si avrebbe: (3 1*3 1), cioe' 3 3 1 ossia 7. In realta' l'espressione espansa correttamente sarebbe dovuta essere: (x 1)(x 1), cioe' (3 1)(3 1) ossia 16. Percio' per produrre il risultato corretto occorre definire la macro in questo modo:
In sostanza non devono esserci spazi fra la parentesi prima degli argomenti ed il nome della macro ed inoltre sono necessarie le parentesi aggiuntive nel testo della macro. Nel file header stdio.h le funzioni getchar e putchar sono definite come macro, per evitare di dover effettuare una chiamata a funzione ad ogni lettura di un carattere. Infatti usare le macro e' piu' veloce delle chiamate a funzioni, ma costa in termini di memoria poiche' il codice della macro e' espanso nel programma ogni volta che viene incontrata una occorrenza che soddisfa la definizione data all'interno della macro. Le funzioni definite come macro possono avere degli argomenti preceduto dal simbolo #: in questi casi tale carattere viene trasformato in una stringa. Ad esempio:
viene espansa come: 'printf ("valore = %d",valore);'. 28.3 Le macro predefinite ed altre direttive
Esistono poi delle macro predefinite che permettono di inserire informazioni aggiuntive nel file eseguibile finale come ad esempio il nome del programma, la data e l'ora di compilazione. Le macro predefinite indicate dallo standard sono:
Nell'ultimo esempio viene stampato un messaggio di errore ed il numero di riga dove tale errore si e' verificato (in questo caso una apertura del file miofile non andata a buon fine). Un'altra direttiva che e' possibile impartire al preprocessore e' la direttiva #error. La sintassi e' la seguente:
quest'istruzione sospende momentaneamente la compilazione per mostrare il messaggio di errore specificato (ed altre informazioni che variano da compilatore a compilatore). Il messaggio non deve essere specificato tra apici. La direttiva #pragma cambia a seconda dell'implemetazione e premette l'esecuzione di istruzioni speciali del compilatore definite dal produttore (a tale scopo consultare la documentazione del compilatore usato). 28.4 Le direttive condizionali
E' possibile impartire le direttive al preprocessore in modo condizionato, utilizzando i seguenti comandi:
L'operatore ## e' utilizzato per concatenare due stringhe, ad esempio: #define concat(a,b)(a)##(b). Infine, la direttiva #undef cancella una precedente definizione di macro.
Inizio della guida Costrutti di controllo Indice I puntatori Copyright (c) 2002-2003 Maurizio Silvestri |