Зачем использовать do {} while (0) в определении макроса?

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

Я встретил код, как показано ниже:

#define ev_io_init(ev,cb,fd,events) \
do { \
  ev_init ((ev), (cb)); \
  ev_io_set ((ev),(fd),(events)); \
} while (0)

Я хочу знать, почему автор использует здесь do { } while (0). Есть ли в этом разница?

#define ev_io_init(ev,cb,fd,events) { \
  ev_init ((ev), (cb)); \
  ev_io_set ((ev),(fd),(events)); \
}

Кстати: код взят из libev, ev_local.h


person ciphor    schedule 29.02.2012    source источник


Ответы (3)


Считайте if( something ) function1(); else function2();

Если function1() на самом деле макрос, просто использование { } требует, чтобы вы опускали точку с запятой в точке использования, но do { } while(0) позволяет использовать точно такой же синтаксис, что и для реальной функции.

(Если вообще не использовать какую-либо блочную конструкцию, это приведет к сгенерированию полностью неработающего кода, natch)

person moonshadow    schedule 29.02.2012

Заключение кода в цикл позволяет директиве препроцессора выполнять несколько операторов без «нарушения» конструкций if-else. Учтите следующее:

#define DO_SOMETHING() a();b();c();

void foo()
{
    // This is ok...
    DO_SOMETHING();
}

void bar()
{
    // ...whereas this would trigger an error.
    if (condition)
       DO_SOMETHING();
    else
       blah();
}

Во втором примере прерывается конструкция if-else, поскольку за тремя операторами следует предложение else. Чтобы обеспечить правильную замену, инструкции в DO_SOMETHING должны быть заключены в do { ... } while(0).

person Linus Kleen    schedule 29.02.2012
comment
конечно, если вы используете такие строки naked if, вы заслуживаете того, чтобы ваш код сломался ... - person Simon; 29.02.2012
comment
@Simon Но разве стиль кодирования ядра Linux не советует нам использовать голые строки if else для одного строчного блока? kernel.org/doc/Documentation/CodingStyle - person CoderSpinoza; 23.11.2015
comment
@CoderSpinoza, очевидно, так, и если бы я работал над ядром Linux, я бы следовал этому стилю. В другом месте я бы этого избегал. - person Simon; 23.11.2015
comment
Во многих репозиториях кода C используется одна строка if без фигурных скобок, и это совершенно нормально. - person Elvis Teixeira; 04.01.2018

do{}while(0) позволяет выйти из цикла:

do{
   expr1;
   foo();
   if ( cond )
      break;
   expr2;
   goo(); 
} while (0);

Это то же самое, что и простой блок {...}, за исключением того, что вы можете прервать выполнение, когда захотите, с помощью оператора break. Вы не можете сделать это в простом блоке кода, если у вас нет нескольких проверок, которые могут быть громоздкими. Он по-прежнему выполняется один раз из-за условия while(0).

person Luchian Grigore    schedule 29.02.2012
comment
... есть, но, пожалуйста, не надо ... - person moonshadow; 29.02.2012
comment
Это уменьшает количество вложений if-else. - person shuva; 09.01.2018