Macro multilínea C: do/while(0) frente al bloque de alcance
macros multiline (1)
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 declaración regular, no en una declaración 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 (<condition>)
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 (<condition>)
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 compilará, porque la rama ''verdadera'' de ''si'' ahora está representada por una declaración compuesta. Y cuando pones un '';'' después de esta declaración compuesta, terminaste toda la instrucción ''if'', orientándote así a la rama ''else'' (de ahí el error de compilación).
Una forma de corregir este problema es recordar no poner '';'' después de macro "invocaciones"
if (<condition>)
CALL_FUNCS(a)
else
bar(a);
Esto se compilará 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 declaración 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 (<condition>)
CALL_FUNCS(a);
else
bar(a);
compilará 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).
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 / } while (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 / }