C многострочный макрос: do/while (0) vs scope block

Возможные дубликаты:
Что нужно использовать во время (0), когда мы определяем макрос?
Почему иногда существуют бессмысленные операторы do/while и if/else в макросах C/С++?
do { … } while (0) what is it good for?

Я видел несколько многострочных макросов C, которые обернуты внутри цикла do/while (0), например:

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

Каковы преимущества (если таковые имеются) написания кода таким образом, в отличие от использования базового блока:

#define FOO \
  { \
    do_stuff_here \
    do_more_stuff \
  }

Ответ 1

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

Андрей Тарасевич:

Вся идея использования версии "do/while" заключается в создании макроса, который будет расширяется в регулярный оператор, а не в составной оператор. Это сделанные для того, чтобы использовать макрос функциональных стилей с использование обычных функций во всех контекстах.

Рассмотрим следующий эскиз кода

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

где "foo" и "bar" являются обычными функциями. Теперь представьте, что вы как заменить функцию 'foo' макросом вышеуказанной природы

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

Теперь, если ваш макрос определен в соответствии со вторым подходом (просто '{' и '}') код больше не будет компилироваться, потому что 'true' ветвь "if" теперь представлена ​​составной инструкцией. И когда вы поместите ';' после этого составного заявления вы закончили целое 'if' , тем самым осировая ветвь "else" (следовательно, ошибка компиляции).

Один из способов исправить эту проблему - запомнить не ставить ';' после макрос "invocations"

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

Это будет компилироваться и работать как ожидалось, но это не равномерно. более элегантным решением является обеспечение того, чтобы макрос расширялся до обычного выражение, а не составное. Один из способов достижения этого - определить макрос следующим образом

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

Теперь этот код

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

будет скомпилирован без проблем.

Однако обратите внимание на небольшое, но важное различие между моим определением из CALL_FUNCS и первой версии вашего сообщения. Я не поставил ; после } while (0). Полагая ; в конце этого определения немедленно уничтожит всю точку использования "do/while" и сделает этот макрос в значительной степени эквивалентен версии составного оператора.

Я не знаю, почему автор кода, который вы цитировали в своем оригинале сообщение ; после while (0). В этой форме оба варианта: эквивалент. Вся идея использования версии "do/while" заключается не в том, чтобы включить этот окончательный ; в макрос (по причинам, которые я объяснил выше).