Подтвердить что ты не робот

Делать while (false) pattern

Возможный дубликат:
Почему иногда существуют бессмысленные операторы do/while и if/else в макросах C/С++?

Почему в макросах требуется do while(false)?

#define LOG(message, ...) \
do { \
Lock<MutualExclusion> lock (logMutex); \

 .... a lot of code ...
} while (false)

Я не думаю, что он служит любой функциональной цели. Я что-то пропускаю?

4b9b3361

Ответ 1

Он превращает блок в один оператор. Если вы просто используете блок (т.е. Код, заключенный в {}), могут произойти странные вещи, например

#define STUFF() \
  { do_something(); do_something_else(); }

if (cond)
    STUFF();
else
    //...

дополнительная полуколока разбивает синтаксис. do {} while(false) вместо этого является одним выражением.

Подробнее об этом и других макро-трюках можно узнать здесь.

Ответ 2

Таким образом, вы вынуждены добавлять точку с запятой в конце макроса, когда используете его. Это распространенная идиома и единственный способ ее принудительного применения.

Ответ 3

Если у кого-то есть код, который делает это:

if (something)
    LOG("My log message");

Это будет расширяться до:

if (something)
    Lock<MutualExclusion> lock (logMutex);
    // A bunch of other code

Это неверно (только первая строка будет находиться в выражении if).

Макрос гарантирует, что вызов макроса находится внутри блока кода.

Ответ 4

Люди используют его, потому что иначе вы можете испортить ваши ifs с помощью составных операторов. Представьте себе,

#define hai int x; \
x = 0;

if (condition)
    hai;
else
    func();

Представьте, как выглядит обработанный исходный код.

if (condition)
   int x;
   x = 0;
else
   func();

О, подождите, теперь наш другой не работает.

Макросы, подобные этому, как правило, не нужны в С++.

Ответ 5

Причиной этой странной практики в #define является инкапсуляция различных назначений в цикл, который выполняется ровно один раз, поэтому макрос можно использовать как функцию. Например, с кодом, который вы опубликовали, можно написать:

if(...)
    LOG(x, y);
else
    // Something else

и он расширяется как

if(...)
    do {...} while(false);
else
    // Something else

Это не сработает без do... while (false), окружающего разные назначения, потому что это будет расширяться как

if(...)
    Lock<MutualExclusion> lock (logMutex);

// Other code... Outside the if statement!

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

Ответ 6

Он обеспечивает локальную область видимости внутри макроса.

Ответ 7

Мне кажется, что он используется только для правил определения области видимости, поэтому Lock<MutualExclusion> выпадает из области видимости в конце блока.

Если это причина для этого, то он совершенно не исправляется:

// some other code...
string s = "oh hai";
{
  Lock<MutualExclusion> lock(logMutex);
  // MAGIC HAPPENS
}
s = "oh bai";