homme.io
Clean.Precise.Quick.
..
PAX ROMANA
SAKURA
Фотография
Философия
Искусство
История
C/C++
DBMS
Oracle
Спорт
Linux
Lua
IT

Infinitum.Aeterna
2024.Китай
Иран в лицах
2023.Иран
2023.06.Москва
2023.Стамбул
2023.ЗИМА
2022.11.Турция
2022.ОСЕНЬ
2022.08.Зубовка
2022.07.Турция
2022.Раменское
2022.ЛЕТО
2022.Архангельское
2022.Парк 50-летия Октября
2022.Санкт-Петербург
2022.Ярославль
2022.03.Зубовка
2022.Кокошкино
2022.Сочи
2022.ВЕСНА
2022.02.Царицыно
2022.Стамбул
2022.02.Коломенское
2022.ЗИМА
2021.Зубовка
2021.ОСЕНЬ
2021.Египет
2021.Раменское
2021.ЛЕТО
2021.Дивеево
2021.Азов
2021.02.Зоопарк
2021.Карелия
2020.Санкт-Петербург
2020.Турция
2020.Аносино
2020.Азов
2020.Верея
2020.Арктика
2020.Греция
2019.Турция
2019.Зубовка
2019.Дагестан
2019.Дагестан+
2019.Египет
2019.Италия
2019.Куликово поле
2019.Калуга
2019.02.Танцы
2019.Байкал
2018.Переславль
2018.Плес
2018.Березка
2018.Крым
2018.Азов
2018.Калининград
2018.Санкт-Петербург
2018.Эльбрус
2017.Турция
2015.Египет
2013.Египет
2013.Рим
Разное

Why we use of do while(0) when we define a macro?

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

Why do they use this rather than define it simply in a {}?

 

You can follow it with a semicolon and make it look and act more like a function. It also works with if/else clauses properly then.

Without the while(0), your code above would not work with

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

since the semicolon after the macro would "eat" the else clause, and the above wouldn't even compile.

 

========

Зачем нужна конструкция do { … } while(0)?

/*
 * All of the callbacks setting methods can be generalized to this:
 */
#define SET_CALLBACK(a)                                         \
do                                                              \
{                                                               \
    if( fgStructure.CurrentWindow == NULL )                     \
        return;                                                 \
    SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback ); \
} while( 0 )

Q: Не понимаю, зачем здесь нужен цикл, ведь он в любом случае выполниться всего одинраз, разве нет?

A:

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

На первый взгляд того же самого можно было бы достичь просто путем заключения самого определения макроса в пару { ... } вместо do { ... } while (0). Однако вариант с { ... } будет обладать одним неприятным недостатком - надо будет постоянно помнить, что его тело представляет из себя { ... }, а после { ... } в С не всегда можно ставить ;. 

Например, если бы тело SET_CALLBACK было заключено просто в { ... }, то вот такой естественно выглядящий код не скомпилировался бы по причине того, что из-за поставленной после SET_CALLBACK(foo) точки с запятой ветка else оказалось оторванной от своего if

if (true)
  SET_CALLBACK(foo); // <- "Лишняя" `;`
else                 // <- Ошибка: оторванный `else`
  /* что-то еще */;

Вот тут-то на сцену и выходит do { ... } while (0). Цикл do/while уникален тем, что является единственной (почти) в языке С грамматической конструкцией, которая формирует блок, и при этом всегда безусловно заканчивается на ;. Благодаря этой замыкающей ; мы можем более естественным образом использовать do { ... } while (0) внутри составных макросов для объединения их в единый statement. В вышеприведенном примере с if ;, указанная после SET_CALLBACK(foo), будет "поглощена" конструкцией do { ... } while (0) и не приведет в "разрушению" целостности if.

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

P.S. Почему авторы языка в свое время решили настоять на включении [теоретически совсем не нужной] замыкающей ; в синтаксис do/while - не совсем ясно, но это было сделано.

sdmrnv, 2021-08-11 [0.496ms, s]