Una macro è un nome che il preprocessore sostituisce con del testo prima che parta il compilatore. Questo è tutto il meccanismo, e ogni regola di questa pagina ne è una conseguenza: le macro non hanno tipi, non rispettano la visibilità, non valutano gli argomenti e non sanno cosa sia una chiamata di funzione. Copiano testo.
Usate con attenzione sono indispensabili: interruttori per la portabilità, macro di asserzione che catturano il numero di riga, costanti in fase di compilazione che funzionano nelle dimensioni degli array. Usate con leggerezza producono bug che sembrano impossibili finché non espandi il file.
Macro semplici
La forma più semplice definisce un nome che sta per un valore:
Per convenzione questi nomi sono in UPPER_SNAKE_CASE, così chi legge capisce a colpo d'occhio che un simbolo è una macro e non una variabile. Qui la convenzione conta più del solito, perché le macro ignorano la visibilità: un #define dentro una funzione vale comunque per il resto del file, e riscriverà senza problemi una variabile con lo stesso nome in un'altra funzione.
#undef NAME rimuove una definizione, così un nome può essere ridefinito più avanti senza un avviso di ridefinizione.
Macro con argomenti
Metti una lista di parametri subito dopo il nome, senza spazi prima della parentesi aperta, e la macro accetta argomenti:
La regola dello spazio è reale: #define SQUARE (x) ((x)*(x)) definisce una macro semplice chiamata SQUARE il cui testo sostitutivo inizia con (x). L'errore del compilatore che ne segue non menzionerà gli spazi.
Le regole delle parentesi
Sono due, ed esistono entrambe perché il corpo viene incollato in un'espressione che non puoi vedere mentre scrivi la macro.
Regola 1: metti tra parentesi ogni parametro. Senza, un argomento che è a sua volta un'espressione viene smembrato dalla precedenza degli operatori:
#define SQUARE_BAD(x) x * x
SQUARE_BAD(2 + 3) /* diventa 2 + 3 * 2 + 3 == 11, non 25 */
Regola 2: metti tra parentesi l'intero corpo. Senza, è l'espressione circostante a smembrare il risultato:
#define DOUBLE_BAD(x) (x) + (x)
10 / DOUBLE_BAD(5) /* diventa 10 / (5) + (5) == 7, non 1 */
Esegui i due errori fianco a fianco con le versioni corrette:
Entrambe le versioni sbagliate compilano senza un solo avviso e producono numeri errati. L'abitudine da prendere è meccanica: racchiudi ogni parametro, poi racchiudi il risultato. ((a) > (b) ? (a) : (b)) sembra pieno di rumore, e il rumore è proprio il punto.
La trappola della valutazione multipla
Le parentesi non possono salvarti dal secondo pericolo. Una macro incolla il testo dell'argomento in ogni punto in cui compare il parametro, quindi un argomento con un effetto collaterale si verifica più di una volta:
La macro si espande in ((i++) > (j) ? (i++) : (j)). Il confronto incrementa i a 6 e confronta 5 con 3; il ramo vero incrementa di nuovo i a 7 e restituisce 6. Quindi m vale 6 e i vale 7, e nessuno dei due è quello che dovrebbe dare "il maggiore tra i e j". Una funzione max(i++, j) sarebbe corretta, perché l'argomento viene valutato una sola volta prima della chiamata.
La stessa trappola colpisce qualsiasi cosa abbia un effetto collaterale: SQUARE(rand()) chiama rand() due volte e moltiplica due numeri diversi. CHECK(read_byte()) consuma due byte.
Due difese, in ordine di preferenza:
- Usa una funzione vera. Se ti serve per più tipi, scrivine una per tipo, oppure usa una funzione
static inlinein un header. - Se deve per forza essere una macro, documenta chiaramente che gli argomenti vengono valutati più di una volta, e tieni i punti di chiamata liberi da effetti collaterali.
Macro su più righe e do-while(0)
Il corpo di una macro può estendersi su più righe se ogni riga tranne l'ultima termina con un backslash. La versione ingenua sembra a posto:
#define LOG_TWICE(msg) \
printf("%s\n", msg); \
printf("%s\n", msg)
E poi si rompe, in silenzio, proprio nel punto in cui conta:
if (verbose)
LOG_TWICE("ciao");
else
printf("silenzio\n");
Dopo la sostituzione l'if controlla solo la prima printf, la seconda viene eseguita sempre, e l'else non ha più un if corrispondente: un errore di compilazione il cui messaggio non indica nulla di utile. Racchiudere il corpo in semplici graffe non va meglio: il ; finale dopo LOG_TWICE("ciao") diventa un'istruzione vuota che chiude l'if, e l'else si rompe di nuovo.
L'idioma che funziona è do { ... } while (0):
do { ... } while (0) è una singola istruzione, esegue il suo corpo esattamente una volta e richiede un punto e virgola dopo, quindi il punto di chiamata si legge come una normale chiamata di funzione e si comporta come tale in ogni contesto di controllo del flusso. Occhio ai backslash: uno spazio di troppo dopo un backslash interrompe la continuazione e produce un errore incomprensibile.
Macro predefinite e schemi di asserzione
Il preprocessore definisce da sé diverse macro, e sono il motivo per cui alcune cose semplicemente non possono essere funzioni:
__FILE__ e __LINE__ si espandono dove sono scritte, quindi metterle dentro una macro cattura la posizione del chiamante. Una funzione non potrebbe farlo: al suo interno riporterebbero sempre il file e la riga della funzione di logging stessa. È esattamente così che la macro standard assert riporta la posizione dell'espressione fallita.
Altri nomi predefiniti utili: __DATE__, __TIME__ e __STDC_VERSION__ (per esempio 201710L per C17).
Due operatori da conoscere
Dentro il corpo di una macro, # trasforma un parametro in un letterale stringa ("stringizing") e ## incolla insieme dei token ("token pasting").
SHOW(width * height) diventa printf("width * height" " = %d\n", (width * height));: i letterali stringa adiacenti vengono uniti dal compilatore, quindi una sola chiamata stampa sia il testo dell'espressione sia il suo valore. È un trucco di debug che vale la pena ricordare.
## è più raro e compare soprattutto nelle macro che generano codice: #define MAKE_VAR(n) int var_##n trasforma MAKE_VAR(3) in int var_3. Usalo con parsimonia; gli identificatori costruiti dal preprocessore non si possono cercare per nome, e questo rende il codice difficile da esplorare.
Macro, funzioni e const a confronto
Usa lo strumento più debole che fa il lavoro:
- Variabile
const:const double PI = 3.14159;ha un tipo, rispetta la visibilità, compare nel debugger e non può essere ridefinita da un header estraneo. Preferiscila per i valori usati a runtime. enum:enum { MAX_USERS = 100 };dà una costante intera con un nome che funziona dove il C richiede una costante in fase di compilazione, con un tipo e una visibilità. Ottima per i limiti interi.- Funzione
static inline: ha il controllo dei tipi, valuta ogni argomento esattamente una volta e i compilatori moderni la espandono in linea proprio come farebbe una macro. È la sostituta giusta di quasi tutte le macro con argomenti. - Macro: quando ti serve
__LINE__, quando la cosa deve funzionare prima che esistano i tipi (dimensioni degli array nel codice più vecchio), quando attivi o disattivi codice con la compilazione condizionale, o quando generi codice ripetitivo.
Un campo in cui le macro restano incontrastate è la dimensione degli array, perché il risultato deve essere una costante in fase di compilazione:
Anche questa ha un limite ben noto: è corretta solo per un vero array. Passale un puntatore, che è ciò che diventa un array quando lo passi a una funzione, e sizeof misura il puntatore, dando una risposta sbagliata con totale sicurezza e senza alcun avviso.
Fare il debug di una macro
Quando una macro si comporta male, non restare a fissarla. Espandila:
gcc -E program.c | tail -30
Il testo sostituito ti dice subito se il problema è una parentesi mancante, una doppia valutazione o un nome che si scontra con qualcos'altro. Compila anche con -Wall -Wextra: GCC e clang aggiungono note "in expansion of macro" che collegano la riga dell'errore segnalato alla definizione.
Prossimo argomento: i file header, dove #define e #include si combinano per permettere a un progetto di estendersi su molti file sorgente senza incollare due volte le stesse dichiarazioni.
Domande frequenti
Cos'è una macro in C?
Un pezzo di testo con un nome che il preprocessore sostituisce nel sorgente prima della compilazione. #define MAX 100 trasforma ogni MAX successivo in 100; #define SQUARE(x) ((x) * (x)) accetta argomenti e li sostituisce in uno schema. Le macro non hanno tipi e non seguono le regole di visibilità: sono sostituzione di testo.
Perché le macro C hanno bisogno di così tante parentesi?
Perché il corpo viene incollato nel codice circostante e poi analizzato tutto insieme. #define SQUARE(x) x * x trasforma SQUARE(2 + 3) in 2 + 3 * 2 + 3, che vale 11 e non 25. Racchiudere ogni argomento e l'intero corpo, ((x) * (x)), fa sì che il testo sostituito si raggruppi come volevi, qualunque cosa ci sia intorno.
Qual è la differenza tra una macro e una funzione in C?
Una funzione viene compilata una volta, ha il controllo dei tipi e valuta ogni argomento esattamente una volta. Una macro viene incollata a ogni uso, non controlla nulla e può valutare un argomento più volte, quindi MAX(i++, j) può incrementare i due volte. Preferisci le funzioni (e const/enum per le costanti); usa le macro per ciò che le funzioni non possono fare, come catturare __LINE__ o generare codice.
Perché una macro su più righe è racchiusa in do { ... } while (0)?
Perché si comporti come una singola istruzione. Un corpo { ... } semplice si rompe quando è seguito da un punto e virgola dentro un if/else (il punto e virgola chiude l'if in anticipo), e una semplice sequenza di istruzioni si rompe in un if senza graffe. do { ... } while (0) è un'unica istruzione che accetta un punto e virgola finale ed esegue il suo corpo esattamente una volta.