Что делать во время (0), когда мы определяем макрос?

Возможный дубликат:
Операторы Do-While и if-else в макросах C/С++

Я читаю ядро ​​linux, и я нашел много таких макросов:

#define INIT_LIST_HEAD(ptr) do { \
    (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

Почему они используют это, а не определяют его просто в {}?

Ответ 1

Вы можете следовать за ним точкой с запятой и заставлять ее выглядеть и действовать скорее как функция. Он также корректно работает с правилами if/else.

Без времени (0) ваш код выше не будет работать с

if (doit) 
   INIT_LIST_HEAD(x);
 else 
   displayError(x);

поскольку точка с запятой после макроса будет "есть" предложение else, и выше не будет даже компилироваться.

Ответ 2

Он позволяет группировать несколько операторов в один макрос.

Предположим, вы сделали что-то вроде:

if (foo) 
    INIT_LIST_HEAD(bar);

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

if (foo)
    (bar)->next = (bar);
    (bar)->prev = (bar);

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

Изменить: дальнейшее объяснение в http://c-faq.com/cpp/multistmt.html и http://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Swallowing-the-Semicolon.html#Swallowing-the-Semicolon