Какая польза от do while(0), когда мы определяем макрос?

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

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

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

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

2 ответа

Решение

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

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

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

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

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

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

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

Другие вопросы по тегам