2011-01-12 18 views
18

Duplicar posibles:
Why are there sometimes meaningless do/while and if/else statements in C/C++ macros?hacer mientras (falso) patrón

¿Por qué es el do while(false) necesaria en las macros de abajo?

#define LOG(message, ...) \ 
do { \ 
Lock<MutualExclusion> lock (logMutex); \ 

.... a lot of code ... 
} while (false) 

No creo que sirva para ningún propósito funcional. ¿Estoy pasando por alto algo?

+3

Abuso grave de macros. –

+0

@Rafe: Por supuesto, las macros son bastante asquerosas para empezar. –

+0

En 'C' macros son muy útiles. Actualmente estoy usando macros para contenedores genéricos. En 'C++' tienes plantillas, bastardos afortunados ;-) – gruszczy

Respuesta

37

Convierte un bloque en una sola instrucción. Si sólo utiliza un bloque (es decir, de código cerrado en {}) cosas extrañas pueden suceder, por ejemplo

#define STUFF() \ 
    { do_something(); do_something_else(); } 

if (cond) 
    STUFF(); 
else 
    //... 

el extra de punto y coma rompe la sintaxis. El do {} while(false) en su lugar es una declaración única.

Puede encontrar más información sobre este y otros macro trucos here.

+4

+1 por buena respuesta. Ojalá pudiera dar otro por no ser un asno mientras que tantos otros lo son. –

+0

No creo que esto afecte al código generado, ¿verdad? –

8

Por lo tanto, se ve obligado a agregar un punto y coma al final de la macro, cuando lo usa. Esta es una expresión común y la única forma de hacerla cumplir.

+0

Por supuesto, esta no es una gran razón. –

+0

@Rafe: sin embargo, es la razón exacta. –

+4

@Rafe: es una práctica estándar establecida. En general, se está de acuerdo en que esta es realmente una * muy * buena razón. –

1

Proporciona alcance local a lo que está dentro de la macro.

7

Si alguien tiene código que hace esto:

if (something) 
    LOG("My log message"); 

que ampliaría a:

if (something) 
    Lock<MutualExclusion> lock (logMutex); 
    // A bunch of other code 

lo cual es incorrecto (sólo la primera línea estaría bajo la instrucción if).

El macro se asegura de que la macro llamada se encuentre dentro de un bloque de código.

+2

Esta es la mitad de la historia, y podría lograrse solo con llaves. La otra mitad de la historia es que no se romperá en otros constructos (el método de llaves simples se rompería si se usara como la única declaración en la cláusula 'si' cuando hay una cláusula' else'. –

+0

Buena información adicional, @David. Gracias. – Jacob

1

Me parece que solo se usa para las reglas de alcance, por lo que Lock<MutualExclusion> queda fuera del alcance al final del bloque.

Si esa es la razón de que, a continuación, es que es completamente unnecesarry:

// some other code... 
string s = "oh hai"; 
{ 
    Lock<MutualExclusion> lock(logMutex); 
    // MAGIC HAPPENS 
} 
s = "oh bai"; 
+0

Creo que esto funcionaría en C# pero no en C. –

+0

@justin: exactamente lo contrario. –

+0

@justin: C no tiene destructores. C++ es el tema en cuestión, en lugar de C#. En cualquier caso, John, puedes argumentar que todas las macros son innecesarias si estás dispuesto a expandir manualmente sus contenidos. –

3

La gente lo usa porque de lo contrario, puede arruinar sus IFS con sentencias compuestas. Imagine

#define hai int x; \ 
x = 0; 

if (condition) 
    hai; 
else 
    func(); 

Imagine cómo es la fuente preprocesada.

if (condition) 
    int x; 
    x = 0; 
else 
    func(); 

Espere, ahora nuestro otro trabajo no funciona.

Sin embargo, macros como esta no son necesarias en C++.

+1

Incluso peor, puede que incluso no haya un error de compilación dado 'if (cond) MACRO; el código else; 'expandiéndose a la barra' if (cond) if (foo); código de else; '. –

2

El motivo de esta práctica extraña en # define es encapsular las diferentes asignaciones dentro de un ciclo que se ejecuta exactamente una vez, por lo que uno puede usar la macro como una función. Por ejemplo, con el código que envió, se puede escribir:

if(...) 
    LOG(x, y); 
else 
    // Something else 

y se expande como

if(...) 
    do {...} while(false); 
else 
    // Something else 

Esto no funcionaría sin el do ... while (falsa) que rodea las diferentes tareas , porque eso puede expandir como

if(...) 
    Lock<MutualExclusion> lock (logMutex); 

// Other code... Outside the if statement! 

también obligando a un punto y coma después de la macro hace que parezca una función y no vas a encontrar errores, ya que ha añadido un punto y coma como después de una functi normales en.

Cuestiones relacionadas