Он всегда используется в макросах, поэтому после вызова требуется точка с запятой, как и при вызове обычной функции.
В вашем примере вы должны написать
__local_irq_save(1);
, а
__local_irq_save(1)
приведет к ошибке об отсутствии точки с запятой. Этого бы не произошло, если бы не было do while. Если бы речь шла только об области видимости, было бы достаточно простой пары фигурных скобок.
Это позволяет отображать код здесь:
if(a) __local_irq_save(x); else ...;
// -> if(a) do { .. } while(0); else ...;
Если бы они просто использовали {..}
, вы бы получили
if(a) { ... }; else ...;
Остальное не принадлежало бы никакому , если
больше, потому что точка с запятой будет следующим оператором и отделяет else
от предыдущего if
. Произойдет ошибка компиляции.
Цель конструкции do {...} while (0)
- превратить группу операторов в один составной оператор. что можно завершить с помощью ;
. Видите ли, в языке C конструкция do / while
обладает одним странным и необычным свойством: даже несмотря на то, что она «работает» как составной оператор, она ожидает в конце ;
. Никакие другие составные конструкции в C не обладают этим свойством.
Благодаря этому свойству вы можете использовать do / while
для написания макросов с несколькими операторами, которые можно безопасно использовать как «обычные» функции, не беспокоясь о том, что находится внутри макроса, как в следующем примере
if (/* some condition */)
__local_irq_save(x); /* <- we can safely put `;` here */
else
/* whatever */;
Ответ уже был дан (так что макрос вынуждает ;
при вызове), но я видел другое использование такого рода операторов : он позволяет вызывать прерывание в любом месте «цикла», при необходимости прерывая его раньше. По сути, это «goto», за которое ваши товарищи-программисты не стали бы вас убивать.
do {
int i = do_something();
if(i == 0) { break; } // Skips the remainder of the logic
do_something_else();
} while(0);
Обратите внимание, что это все еще довольно запутанно, поэтому я не рекомендую его использовать.
Он использует действие макроса как реальный оператор или вызов функции.
Оператор представляет собой либо {список-выражений}
, либо выражение;
, поэтому возникает проблема при определении макросов, которым требуется более одного выражения, потому что если вы используете { }
тогда синтаксическая ошибка возникнет, если вызывающий макрос вполне разумно добавит ;
перед else.
if(whatever)
f(x);
else
f(y);
Если f ()
- это макрос с одним оператором, хорошо, но что, если это макрос и что-то сложное? Вы получите , если (...) {s1; s2; }; иначе ...
и это не сработает.
Таким образом, автор макроса должен либо преобразовать ее в реальную функцию, либо заключить конструкцию в один оператор, либо использовать расширение GNU.
Шаблон do .. while (0)
- это подход «обертывания конструкции».
Похоже, что это здесь просто для определения. Это похоже на:
if (true)
{
// Do stuff.
}
edit
Я не вижу этого в вашем примере, но возможно, что один из этих вызовов функции на самом деле является макросом, и в этом случае есть одно ключевое различие между do/while(0) и if(true), которое заключается в том, что первый позволяет continue
и break
.