Storia della questione
I macro con parametri sono una parte importante del preprocessore C, nati per l'inserimento rapido di frammenti di codice ripetitivi e per semplificare il debug. Vengono utilizzati per piccole funzioni, inline o ottimizzazione.
Problema
I macro non controllano i tipi e non eseguono una sostituzione completa al di fuori della semplice sostituzione testuale. Gli errori si verificano a causa dell'assenza di parentesi e della sostituzione di espressioni con effetti collaterali.
Soluzione
Prevedere parentesi attorno ai parametri e alle definizioni dei macro, evitare effetti collaterali negli argomenti e utilizzare funzioni inline per casi più complessi.
Esempio di codice:
#define MAX(a, b) ((a) > (b) ? (a) : (b)) int x = 5, y = 10; int z = MAX(x++, y++); // Chiamata pericolosa!
Caratteristiche principali:
Sostituisce sempre il macro il codice completamente come una funzione?
No! Il macro è solo una sostituzione testuale prima della compilazione, può comportarsi in modo diverso rispetto a una funzione se gli argomenti sono espressioni con effetti collaterali.
Si può utilizzare qualsiasi chiamata (compresi ++, --) come parametro del macro?
È estremamente pericoloso. Gli effetti collaterali si verificheranno più di una volta se il parametro appare nel macro più di una volta.
Esempio di codice:
// Questa chiamata aumenterà x o y più di 1 MAX(x++, y++)
Come includere correttamente le parentesi nelle dichiarazioni dei macro?
Circondare sia i parametri sia l'espressione all'interno del macro con parentesi, per evitare errori di assiomaticità quando viene chiamato all'interno di altre espressioni.
In azienda per anni è stato definito il macro #define SQUARE(x) xx, e veniva utilizzato per espressioni come SQUARE(a+1). Si sono verificati errori inaspettati: l'espressione veniva espansa come a+1a+1, che è diversa da (a+1)*(a+1).
Pro:
Il macro SQUARE è stato scritto con parentesi complete: #define SQUARE(x) ((x)*(x)). Il suo utilizzo è standardizzato e documentato.
Pro: