• Non ci sono risultati.

Il preprocessore C

N/A
N/A
Protected

Academic year: 2021

Condividi "Il preprocessore C"

Copied!
6
0
0

Testo completo

(1)

Il preprocessore C

Ver. 2.4

© 2010 - Claudio Fornaro - Corso di programmazione in C

Funzionalità

Modifica il codice C prima che venga eseguita la traduzione vera a propria

Le direttive al preprocessore riguardano:

inclusione di file (#include)

definizione di simboli (#define)

sostituzione di simboli (#define)

compilazione condizionale (#if)

macroistruzioni con parametri (#define)

Non essendo istruzioni C non richiedono il ‘;’ finale

3

Inclusione di file

La riga con #include viene sostituita dal contenuto testuale del file indicato

#include <stdio.h>

Il nome del file può essere completo di percorso

Ha due forme:

#include <file.h>

Il file viene cercato nelle directory del compilatore

#include "file.h"

Il file viene cercato primanella directory dove si trova il file C e poi, se non trovato, nelle directory del compilatore

4

Inclusione di file

I file inclusi possono a loro volta contenere altre direttive #include

La direttiva #include viene in genere collocata in testa al file sorgente C, prima della prima funzione

Generalmente, i file inclusi non contengono codice eseguibile, ma solo dichiarazioni (es.

prototipi e variabili extern) e altre direttive

(2)

Definizione di simboli

#define nome

definisce il simbolo denominato nome

#define DEBUG

I simboli vengono utilizzati dalle altre direttive del preprocessore (ad es. si può verificare se un simbolo è stato definito o no con #if)

Lo scope di nome si estende dalla riga con la definizione fino alla fine di quel file sorgente e non tiene conto dei blocchi di codice

nome ha la stessa sintassi di un identificatore (nome di variabile), non può contenere spazi e viene per convenzione scritto in maiuscolo

#undef nome

annulla una #define precedente

Sostituzione di simboli

Sono dette anche macro o macroistruzioni

#define nome testo_sostitutivo

sostituisce i caratteri di nome con i caratteri di testo_sostitutivo in ogni punto del programma dove nome appare come identificatore (ossia sembra una variabile)

#define MAX 100

...

for (i=0; i<MAX; i++)

La sostituzione (detta anche “espansione”) avviene prima della compilazione vera e propria, quindi il compilatore non troverà la riga di codice precedente, ma la seguente:

for (i=0; i<100; i++)

7

Sostituzione di simboli

nome non può essere definito più volte

nome ha la sintassi degli identificatori, viene per convenzione scritto tutto maiuscolo se testo_sostitutivo è una quantità costante (ossia non si tratta di una macro con argomenti )

testo_sostitutivo termina a fine riga:

può contenere spazi

può utilizzare nomi di #define precedenti

se manca, si ha la semplice definizione di nome e quindi tutte le occorrenze di nome sono eliminate

può continuare su più righe purché ogni riga da continuare termini con il carattere ‘\’ (dal punto di vista logico si tratta di una sola lunga riga)

8

Sostituzione di simboli

L’ordine di elencazione delle #define non è rilevante: dopo una sostituzione su una riga, questa viene considerata nuovamente per verificare se quanto ottenuto può essere sottoposto ad un’altra sostituzione

#define C 3

#define B C

#define A B

trasforma ogni A in B, ogni B in C e ogni C in 3, quindi tutte le A, le B e le C in 3

Se un nome è stato sostituito da un’espansione

e compare nuovamente per effetto di altre

espansioni, non viene sostituito nuovamente

(3)

Sostituzione di simboli

Attenzione: essendo una semplice sostituzione di caratteri , si può incorrere in errori

Esempio: il seguente ciclo non va fino a 202

#define MAX 100+1 ...

for (i=0; i<MAX*2; i++)

In realtà va fino a 102 in quanto la sostituzione produce il seguente codice:

for (i=0; i<100+1*2; i++)

Per evitare il problema a priori, è possibile indicare il valore tra parentesi nella define:

#define MAX (100+1)

Macro con argomenti

Sembra una chiamata di funzione con

parametri, invece è un’espansione di macro:

esecuzione più veloce, programma più grande

#define max(A,B) ((A)>(B)?(A):(B))

I simboli A e B sono sostituiti dagli argomenti presenti nella “chiamata” della macro

La prima parte della #define non può avere spazi intermedi, nell’utilizzo possono esserci

Esempio

x = max(p+q, r+s); viene espansa in x = ((p+q)>(r+s)?(p+q):(r+s));

Si noti che funziona per tutti i tipi di dati

11

Macro con argomenti

Attenzione agli effetti collaterali:

max(i++,j++) viene sostituita da ((i++)>(j++)?(i++):(j++))

e il valore più grande tra i e j viene incrementato due volte

Attenzione alle parentesi:

#define quadrato(x) (x)*(x) chiamata come quadrato(z+1) viene correttamente sostituita da (z+1)*(z+1)

#define quadrato(x) x*x

chiamata come quadrato(z+1) viene erroneamente sostituita da z+1*z+1

12

Macro con argomenti

In testo_sostitutivo il nome di un parametro preceduto da un # viene sostituito

dall’argomento racchiuso tra virgolette

#define eprint(expr) \

printf(#expr "=%g\n", expr) la macro eprint(x/y) viene sostituita da:

printf("x/y" "=%g\n", x/y)

e le due stringhe vicine vengono concatenate dal compilatore in "x/y=%g\n"

L’operatore di preprocessore ## concatena due argomenti rimuovendo gli spazi intermedi

#define concat(uno,due) uno ## due

concat(nome,6) viene sostituito da nome6

(4)

Macro composte

Il corpo della macro ( testo_sostitutivo ) può contenere più istruzioni C

#define swap(x,y) t=x; x=y; y=t;

La macro precedente viene chiamata come:

swap(a,b) 

Per chiamarla come fosse una funzione void, è sufficiente non indicare all’estrema destra nella definizione il punto e virgola swap(a,b);  CON ‘;’

Macro composte

Perché la macro composta restituisca un valore come una funzione, se possibile si separano le istruzioni mediante virgole (dà come valore quello dell’espr. più a destra)

#define maxswap(x,y) \

(t=x, x=y, y=t, x>y?x:y) chiamata come: maxswap(a,b);

Se serve definire una variabile temporanea per la macro, si crea un blocco con una coppia di parentesi graffe:

#define swap(x,y) \

{ int t; t=x; x=y; y=t; } Questa macro deve essere chiamata senza il ‘;’

swap(a,b)

15

Macro composte

Per poter chiamare anche la macro precedente con il ‘;’ a fine istruzione così che sembri una funzione, si scrivono le istruzioni all’interno di un ciclo do-while fittizio (sempre falso, non lo ripete mai) e privo del ‘;’ finale:

#define swap(x,y) \

do { \

int t; t=x; x=y; y=t; \ }while (0)

Questa macro deve essere chiamata con il ‘;’

finale:

swap(a,b);

16

Inclusione condizionale

Permette di include o escludere parte del codice dalla compilazione e dal preprocessing stesso

#if espressione_1 istruzioni

#elif espressione_2 istruzioni

...

#else istruzioni

#endif

Solo uno dei gruppi di istruzioni sarà elaborato

dal preprocessore e poi compilato

(5)

Inclusione condizionale

Le espressioni devono essere costanti intere (non possono contenere sizeof(), cast o costanti enum), sono considerate vere se !=0

L’espressione defined(nome) produce 1 se nome è stato definito (con #define), 0 altrimenti

#ifdef nome equivale a:

#if defined(nome)

e verifica che nome sia definito

#ifndef nome equivale a:

#if !defined(nome)

e verifica che nome non sia definito

Inclusione condizionale

Esempio

Per far compilare parti diverse a seconda del sistema operativo, si può usare lo schema seguente (il simbolo _WIN32 viene definito da tutti i compilatori Win32):

#ifdef _WIN32

if (_oneexit(funz)==NULL) abort();

#else

atexit(funz);

#endif

Sono due funzioni quasi equivalenti, la prima esiste solo sui sistemi Win32, la seconda è standard

19

Inclusione condizionale

Nel caso in cui un file incluso ne includa a sua volta altri, per evitare di includere più volte lo stesso file, si può usare lo schema seguente (quello che segue è il file hdr.h):

#ifndef HDR

#define HDR

... contenuto di <hdr.h>

#endif

Se venisse incluso una seconda volta, il simbolo HDR sarebbe già definito e il

contenuto non verrebbe nuovamente incluso nella compilazione

20

Inclusione condizionale

Per escludere dalla compilazione un grosso blocco di codice (anche con commenti):

#if 0

codice da non eseguire

#endif

Per isolare istruzioni da usare solo per il debug:

#ifdef DEBUG

printf("Valore di x: %d\n", x);

#endif

La #define DEBUG viene eliminata a

programma ultimato (spesso il simbolo DEBUG

viene definito dal compilatore stesso se in

configurazione debug)

(6)

Macro predefinite

Sono simboli definiti dal preprocessore:

__DATE__Data di compilazione del file sorgente nel formato di asctime() (in <time.h>) __FILE__Nome del file corrente tra virgolette

__LINE__Numero di linea della riga corrente nel file sorgente, può essere alterato da #line __STDC__Indica che il compilatore è completamente

aderente allo standard ANSI e non fornisce alcuna estensione

__TIME__Ora di compilazione del file sorgente nella forma hh:mm:ss.

__TIMESTAMP__Data e ora di compilazione del file

Macro predefinite

La direttiva #line può essere seguita da un numero intero per impostare il valore di

__LINE__ della riga corrente del codice C, la numerazione delle righe successive prosegue da quel valore

#line 100

La direttiva #line può inoltre impostare un nuovo nome di file

#line 100 "file1.c"

Il valore di __LINE__ e il nome del file vengono usati nelle informazioni di diagnostica fornite dal compilatore

23

Esercizi

1.

Scrivere una macro swap(t,x,y) che scambi il valore di due argomenti di tipo t.

2.

Scrivere una macro printArray(v,n) che visualizzi il contenuto del vettore v di

lunghezza n.

3.

Scrivere una macro sumArray(v,n,sum)

che sommi gli n valori del vettore v e metta il

risultato in sum.

Riferimenti

Documenti correlati

Naturalmente, le preferenze di spesa riflettono scelte politiche ed è proprio per questo motivo che la questione, tutta politica, del futuro delle relazioni Stati Uniti – Europa

vimento; poiché oltre ad amarsi già tanto fra loro, questa era la prima dolorosa partenza dopo l'incancellabile data della Madonna della Neve, ed era quasi

 Se il codice sorgente non contiene errori, l'invocazione del comando (1) produce nella directory corrente un file chiamato &#34;a.out&#34;, che è il risultato della

Nel caso che l’elenco contenga un biglietto corrispondente ad un settore non in vendita per l’evento in oggetto (ossia un settore non presente nel file settori.txt) deve essere

- Descrizione del programma delle indagini e delle prove geotecniche (anche in relazione alla modellazione geologica, e assunte totalmente da questa). - Planimetria

Contratto a tempo indeterminato a tutele crescenti Sarà efficace se si va ad una riduzione delle attuali tipologie contrattuali che nascondono vera precarietà come i contratti

Calcolare il numero delle matrici in X che non soddisfano nessuna delle seguenti condizioni:. a) la terza colonna ha tutti gli elementi nulli; b) la prima riga ha tutti gli

[r]