Palavras-chave: C, macro, multi-statement, cpp, pré-processador, preprocessor
Com alguma freqüência é necessário de definir macros com múltiplos comandos (statements) que possam ser usados de forma sintaticamente equivalente a chamadas de função. Nesse caso, não basta definir uma seqüência como:
#define foo(x) a1(x); a2(x)
Isso seria desastroso após um if, por exemplo. Tampouco adiantaria delimitar o bloco com chaves, o que não funcionaria numa situação como:
if (y) foo(z); else return;
Como, então, podemos definir tais macros? A resposta é: utilizando expressões “do {…} while(0)”, cuja utilidade em outras situações é bastante duvidosa. Veja o exemplo:
#define foo(x) do { a1(x); a2(x); } while (0)
Definindo macros dessa forma, cumprimos nosso objetivo: apesar da declaração aparentemente estranha, seu uso é equivalente a uma chamada de função em qualquer caso, incluindo loops e condicionais.
Seria legal dizer porque não é usado simplesmente um bloco, como em
#define foo(x) { a1(x); a2(x); }
Algo legal sobre isso: http://kernelnewbies.org/FAQ/DoWhile0
Concordo com o Felipe, até porque eu costumava usar apenas
#define foo(x) { a1(x); a2(x); }
e nunca tive problemas. Se puder explicar ou tiver alguma fonte, ficaria grato.
Off.: Estou gostando muito do blog. Vocês estão de parabéns.
Quanto à fonte, a que o Felipe passou explica tudo. Mas ainda assim acho interessante explicar para quem não se vira no inglês.
Expandindo if (y) foo(z); else return; com foo(x) definido como um bloco simples, temos:
if (y) { … }; else return;
o que não é uma construção válida em C. Basta fazer um teste:
$ cat a.c
#define foo(x) { a1(x); a2(x); }
main(int y) { if (y) foo(y); else return; }
$ gcc a.c
a.c: In function ‘main’:
a.c:2: error: expected expression before ‘else’