Macro multilínea C: do / while (0) frente al bloque de scope

Posibles duplicados:
¿De qué sirve hacer mientras (0) cuando definimos una macro?
¿Por qué a veces hay sentencias do / while y if / else sin sentido en las macros C / C ++?
hacer {…} mientras (0) ¿para qué sirve?

He visto algunas macros C multilínea que están envueltas dentro de un ciclo do / while (0) como:

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

¿Cuáles son los beneficios (si corresponde) de escribir el código de esa manera en lugar de usar un bloque básico?

 #define FOO \
   {\
     do_stuff_here \
     do_more_stuff \
   }

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

Andrey Tarasevich:

La idea de usar la versión ‘do / while’ es hacer una macro que se expandirá en una statement regular, no en una statement compuesta. Esto se hace para hacer que el uso de macros de estilo de función sea uniforme con el uso de funciones comunes en todos los contextos.

Considere el siguiente esbozo de código

if () foo(a); else bar(a); 

donde ‘foo’ y ‘bar’ son funciones ordinarias. Ahora imagine que desea reemplazar la función ‘foo’ por una macro de la naturaleza anterior

 if () CALL_FUNCS(a); else bar(a); 

Ahora, si su macro se define de acuerdo con el segundo enfoque (solo ‘{‘ y ‘}’), el código ya no se comstackrá, porque la twig ‘verdadera’ de ‘si’ ahora está representada por una statement compuesta. Y cuando pones un ‘;’ después de esta statement compuesta, terminaste toda la instrucción ‘if’, orientándote así a la twig ‘else’ (de ahí el error de comstackción).

Una forma de corregir este problema es recordar no poner ‘;’ después de macro “invocaciones”

 if () CALL_FUNCS(a) else bar(a); 

Esto se comstackrá y funcionará como se espera, pero esto no es uniforme. La solución más elegante es asegurarse de que la macro se expanda en una statement regular, no en una compuesta. Una forma de lograr eso es definir la macro de la siguiente manera

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

Ahora este código

 if () CALL_FUNCS(a); else bar(a); 

comstackrá sin ningún problema.

Sin embargo, tenga en cuenta la pequeña pero importante diferencia entre mi definición de CALL_FUNCS y la primera versión de su mensaje. No puse una ; después } while (0) . Poniendo un ; al final de esa definición, se anularía inmediatamente todo el punto de utilizar ‘do / while’ y la macro sería prácticamente equivalente a la versión de la sentencia compuesta.

No sé por qué el autor del código que citó en su mensaje original lo puso ; después de un while (0) . De esta forma, ambas variantes son equivalentes. La idea de usar la versión ‘do / while’ no es incluir esta final ; en la macro (por las razones que expliqué arriba).