2009-07-01 18 views
146

Possibili duplicati:
What’s the use of do while(0) when we define a macro?
Why are there sometimes meaningless do/while and if/else statements in C/C++ macros?
do { … } while (0) what is it good for?C multilinea macro: fare/while (0) vs blocco portata

ho visto alcuni multilinea C macro che sono racchiusi in un ciclo do/while (0) come:

 
#define FOO \ 
    do { \ 
    do_stuff_here \ 
    do_more_stuff \ 
    } while (0) 

Quali sono i vantaggi (se presenti) di scrivere il codice in questo modo invece di utilizzare un blocco di base:

 
#define FOO \ 
    { \ 
    do_stuff_here \ 
    do_more_stuff \ 
    } 
+4

Duplicati: http://stackoverflow.com/questions/923822/ e http://stackoverflow.com/questions/154136/ e http://stackoverflow.com/questions/257418/ – sth

+0

In realtà c'è un altro modo per sistemare le cose. ({...}) può fare la stessa cosa di {} mentre (0). Rif: http://www.bruceblinn.com/linuxinfo/DoWhile.html – Nybble

risposta

212

http://bytes.com/groups/c/219859-do-while-0-macro-substitutions

Andrey Tarasevich:

L'intera idea di usare 'fare/mentre 'versione è di creare una macro che sarà espandersi in un'istruzione regolare, non in un'istruzione composta. Questo è eseguito per rendere uniforme l'uso di macro in stile funzione con l'uso di di ordinarie funzioni in tutti i contesti.

Si consideri il seguente codice schizzo

if (<condition>) 
    foo(a); 
else 
    bar(a); 

dove 'foo' e 'bar' sono funzioni ordinarie. Ora immaginate che ti sentiresti di piace per sostituire la funzione 'foo' con una macro della natura sopra

if (<condition>) 
    CALL_FUNCS(a); 
else 
    bar(a); 

Ora, se la macro è definita in accordo con il secondo approccio (solo '{' e '} ') il codice non verrà più compilato, perché il' vero 'ramo di' if 'è ora rappresentato da un'istruzione composta. E quando hai metti un ';' dopo questa dichiarazione composta, hai terminato l'intera istruzione 'if' , rendendo quindi orfano il ramo 'else' (da cui l'errore di compilazione).

Un modo per correggere questo problema è ricordare di non inserire ";" dopo macro "invocazioni"

if (<condition>) 
    CALL_FUNCS(a) 
else 
    bar(a); 

Questo compilerà e funzionano come previsto, ma questo non è uniforme. La soluzione più elegante è quella di assicurarsi che la macro si espanda in una normale istruzione , non in una composita. Un modo per raggiungere questo obiettivo è quello di definire la macro come segue

#define CALL_FUNCS(x) \ 
do { \ 
    func1(x); \ 
    func2(x); \ 
    func3(x); \ 
} while (0) 

Ora questo codice

if (<condition>) 
    CALL_FUNCS(a); 
else 
    bar(a); 

compilerà senza problemi.

Tuttavia, notare la piccola ma importante differenza tra la mia definizione di CALL_FUNCS e la prima versione nel messaggio. Non ho inserito uno ; dopo il } while (0).Mettere un alla fine di quella definizione annullerebbe immediatamente l'intero punto dell'utilizzo di "do/while" e rendere quella macro praticamente equivalente alla versione dell'istruzione composta.

Non so perché l'autore del codice che hai citato nel tuo messaggio originale metta questo ; dopo while (0). In questa forma entrambe le varianti sono equivalenti a . L'intera idea alla base della versione 'do/while' non è quella di includere questo finale ; nella macro (per i motivi che ho spiegato sopra ).

+35

Il post originale è stato creato da me in 'comp.lang.c'. 'bytes.com' sembra" appropriarsi "del contenuto di' comp.lang.c' senza fare alcun riferimento alla fonte. – AnT