2010-10-12 23 views
15

Ho trovato questo mentre leggevo qualche codice sorgente.C++ void cast e operatore virgola in un #define

#define MACRO(x) if((void) 0, (x)); else some_func(); 

Non capisco appieno le ragioni dietro l'operatore virgola e il cast del vuoto. Questo probabilmente ha qualcosa a che fare con la protezione dalle macro, so che a volte viene usato lo (void)0 per proteggere i cascami else in macro come in if(...) then foo(); else (void)0.

Qualche idea sul perché l'operatore è la virgola?

edit: sto iniziando a pensare che questo ha qualcosa a che fare con la owl(0,0).

+0

Sei sicuro che anche compila? – ronag

+0

@ronag: sì, compila. il cast to void è un bel trucco se ti piace scrivere 'return f();' da una funzione void quando 'f' non è vuoto. – ybungalobill

+1

Sono curioso di sapere se è equivalente a '#define MACRO (X) if (! (X)) {some_func()}' – Arun

risposta

8

Suppongo che il trucco venga utilizzato per impedire all'utente di dichiarare le variabili nella condizione if. Come probabilmente sapete, in C++ è legale fare questo

if (int i = some_func()) { 
    // you can use `i` here 
} 
else { 
    // and you can use `i` here 
} 

L'uso di operatore virgola in questa definizione impedirà l'utilizzo di macro come

MACRO(int i = some_func()); 

e obbligare l'utente ad utilizzare solo espressioni come argomento.

+0

Vuoi dire 'i' invece di' x', sì? – sje397

+0

Quello che ho pensato, ma per citare Charles, è vero anche qui: "... cosa ((void) 0, x) è presumibilmente per evitare che una semplice coppia extra di parentesi non sarebbe se ((x)), altrimenti some_func(); ". – ybungalobill

+0

@ybungalobill: Sì, è vero ... E extra'() 'lo risolverebbe in un molto più semplice. – AnT

4

La conversione del vuoto è assolutamente da evitare di chiamare un sovraccarico operator , poiché non è possibile sovraccaricare con un parametro void. Questo garantisce che (void)0, non ha alcun effetto.

Perché l'operatore virgola è presente? Una buona domanda Davvero non lo so.

+3

Non capisco. Puoi spiegare più in dettaglio cosa '((void) 0, x)' si suppone difenda dal fatto che una semplice coppia extra di parentesi non 'if ((x)); else some_func(); '? –

+0

@Charles, hai ragione. – ybungalobill

2

Questo sembra un po 'come se qualcuno avesse iniziato con un codice che includeva uno assert, pre-elaborato e trasformato il risultato in una macro. Quando NDEBUG è definito, assert deve trasformarsi in quasi nulla - ma, sintatticamente, deve ancora produrre un codice segnaposto. Ad esempio, si è permesso di usarlo in una situazione come:

assert(x), *x = 1; 

Quando si compila questo con NDEBUG definita, deve ancora compilare, ma il assert non deve fare nulla. Per supportare qualcosa che, assert è tipicamente definito in questo modo:

#undef assert 
#ifdef NDEBUG 
#define assert(x) ((void)0) 
#else 
#define assert(x) ((!!x) || __failassert(x, __FILE__, __LINE__)) 
#endif 

Quindi, se qualcuno ha iniziato con il codice come sopra, e poi guardò la versione pre-elaborato (con NDEBUG definito), vedrebbero qualcosa come:

((void *)0), *x = 1; 

... e se non hanno capito molto bene il codice, potrebbero pensare che lo ((void)0) significasse veramente/compiuto qualcosa.

+0

Buon ragionamento, ma non sono sicuro che sia la vera ragione. –

+0

Non sono * sicuro * è la vera ragione o - in effetti, probabilmente nessuno, ma l'autore originale può fare qualsiasi cosa se non indovinare, e anche lui potrebbe non ricordare per certo ... –

+0

questo "pazzo" funziona con l'originale MACRO: #define CRAZY 0)); if ((1 – user396672

Problemi correlati