C многострочный макрос: do / while (0) против блока области видимости [duplicate]

Possible Duplicates:
What’s the use of do while(0) when we define a macro?
Why are there sometimes meaningless do/while and if/else statements in C/C++ macros?
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 \
  }
 sth01 июл. 2009 г., 06:19
 Nybble03 авг. 2016 г., 21:51
На самом деле есть еще один способ сделать все правильно. ({...}) может делать то же самое, что и do {} while (0). Ref:bruceblinn.com/linuxinfo/DoWhile.html

Ответы на вопрос(1)

Решение Вопроса

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

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

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

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

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

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

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

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

Один из способов решения этой проблемы - помнить, что не нужно ставить & apos ;; & apos; после макрос "вызовы"

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' версия не для включить этот финал; в макрос (по причинам, которые я объяснил выше).

 23 окт. 2009 г., 08:30
Оригинальный пост был сделан мной вcomp.lang.c. bytes.com по-видимому, "присваивает" содержаниеcomp.lang.c без каких-либо ссылок на источник.

Ваш ответ на вопрос