Le macro sono pezzi di testo copiati / incollati che il pre-processore inserirà nel codice originale; l'autore della macro spera che la sostituzione produca un codice valido.
Ci sono tre buoni "consigli" per riuscirci:
Aiuta la macro a comportarsi come un vero codice
Il codice normale di solito termina con un punto e virgola. Se l'utente visualizza il codice che non ne ha bisogno ...
doSomething(1) ;
DO_SOMETHING_ELSE(2) // <== Hey? What's this?
doSomethingElseAgain(3) ;
Ciò significa che l'utente si aspetta che il compilatore produca un errore se il punto e virgola è assente.
Ma il vero vero buon motivo è che a un certo punto, l'autore della macro dovrà forse sostituire la macro con una funzione autentica (forse in linea). Quindi la macro dovrebbe comportarsi davvero come una.
Quindi dovremmo avere una macro che necessita di punti e virgola.
Produrre un codice valido
Come mostrato nella risposta di jfm3, a volte la macro contiene più di un'istruzione. E se la macro viene utilizzata all'interno di un'istruzione if, questo sarà problematico:
if(bIsOk)
MY_MACRO(42) ;
Questa macro potrebbe essere espansa come:
#define MY_MACRO(x) f(x) ; g(x)
if(bIsOk)
f(42) ; g(42) ; // was MY_MACRO(42) ;
La g
funzione verrà eseguita indipendentemente dal valore di bIsOk
.
Ciò significa che dobbiamo aggiungere un ambito alla macro:
#define MY_MACRO(x) { f(x) ; g(x) ; }
if(bIsOk)
{ f(42) ; g(42) ; } ; // was MY_MACRO(42) ;
Produrre un codice valido 2
Se la macro è simile a:
#define MY_MACRO(x) int i = x + 1 ; f(i) ;
Potremmo avere un altro problema nel seguente codice:
void doSomething()
{
int i = 25 ;
MY_MACRO(32) ;
}
Perché si espanderebbe come:
void doSomething()
{
int i = 25 ;
int i = 32 + 1 ; f(i) ; ; // was MY_MACRO(32) ;
}
Questo codice non verrà compilato, ovviamente. Quindi, ancora una volta, la soluzione utilizza un ambito:
#define MY_MACRO(x) { int i = x + 1 ; f(i) ; }
void doSomething()
{
int i = 25 ;
{ int i = 32 + 1 ; f(i) ; } ; // was MY_MACRO(32) ;
}
Il codice si comporta di nuovo correttamente.
Combinazione di semi-colon + effetti scope?
Esiste un linguaggio C / C ++ che produce questo effetto: Il ciclo do / while:
do
{
// code
}
while(false) ;
Il do / while può creare un ambito, incapsulando così il codice della macro e alla fine ha bisogno di un punto e virgola, espandendosi così nel codice che ne ha bisogno.
Il bonus?
Il compilatore C ++ ottimizzerà il ciclo do / while, poiché il fatto che la sua post-condizione sia falsa è noto al momento della compilazione. Ciò significa che una macro come:
#define MY_MACRO(x) \
do \
{ \
const int i = x + 1 ; \
f(i) ; g(i) ; \
} \
while(false)
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
MY_MACRO(42) ;
// Etc.
}
si espanderà correttamente come
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
do
{
const int i = 42 + 1 ; // was MY_MACRO(42) ;
f(i) ; g(i) ;
}
while(false) ;
// Etc.
}
e viene quindi compilato e ottimizzato come
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
{
f(43) ; g(43) ;
}
// Etc.
}
void
tipo alla fine ... like ((void) 0) .