Что действительно “делает {…}, в то время как (0)” делают точно в коде ядра? [дубликат]

20
задан Community 23 May 2017 в 11:53
поделиться

6 ответов

Он всегда используется в макросах, поэтому после вызова требуется точка с запятой, как и при вызове обычной функции.

В вашем примере вы должны написать

__local_irq_save(1);

, а

__local_irq_save(1)

приведет к ошибке об отсутствии точки с запятой. Этого бы не произошло, если бы не было do while. Если бы речь шла только об области видимости, было бы достаточно простой пары фигурных скобок.

25
ответ дан 29 November 2019 в 22:42
поделиться

Это позволяет отображать код здесь:

if(a) __local_irq_save(x); else ...;

// -> if(a) do { .. } while(0); else ...;

Если бы они просто использовали {..} , вы бы получили

if(a) { ... }; else ...; 

Остальное не принадлежало бы никакому , если больше, потому что точка с запятой будет следующим оператором и отделяет else от предыдущего if . Произойдет ошибка компиляции.

24
ответ дан 29 November 2019 в 22:42
поделиться

Цель конструкции do {...} while (0) - превратить группу операторов в один составной оператор. что можно завершить с помощью ; . Видите ли, в языке C конструкция do / while обладает одним странным и необычным свойством: даже несмотря на то, что она «работает» как составной оператор, она ожидает в конце ; . Никакие другие составные конструкции в C не обладают этим свойством.

Благодаря этому свойству вы можете использовать do / while для написания макросов с несколькими операторами, которые можно безопасно использовать как «обычные» функции, не беспокоясь о том, что находится внутри макроса, как в следующем примере

if (/* some condition */)
  __local_irq_save(x); /* <- we can safely put `;` here */
else
  /* whatever */;
11
ответ дан 29 November 2019 в 22:42
поделиться

Ответ уже был дан (так что макрос вынуждает ; при вызове), но я видел другое использование такого рода операторов : он позволяет вызывать прерывание в любом месте «цикла», при необходимости прерывая его раньше. По сути, это «goto», за которое ваши товарищи-программисты не стали бы вас убивать.

do {
    int i = do_something();
    if(i == 0) { break; } // Skips the remainder of the logic
    do_something_else();
} while(0);

Обратите внимание, что это все еще довольно запутанно, поэтому я не рекомендую его использовать.

5
ответ дан 29 November 2019 в 22:42
поделиться

Он использует действие макроса как реальный оператор или вызов функции.

Оператор представляет собой либо {список-выражений} , либо выражение; , поэтому возникает проблема при определении макросов, которым требуется более одного выражения, потому что если вы используете { } тогда синтаксическая ошибка возникнет, если вызывающий макрос вполне разумно добавит ; перед else.

if(whatever)
  f(x);
else
  f(y);

Если f () - это макрос с одним оператором, хорошо, но что, если это макрос и что-то сложное? Вы получите , если (...) {s1; s2; }; иначе ... и это не сработает.

Таким образом, автор макроса должен либо преобразовать ее в реальную функцию, либо заключить конструкцию в один оператор, либо использовать расширение GNU.

Шаблон do .. while (0) - это подход «обертывания конструкции».

2
ответ дан 29 November 2019 в 22:42
поделиться

Похоже, что это здесь просто для определения. Это похоже на:

if (true)
{
    // Do stuff.
}

edit

Я не вижу этого в вашем примере, но возможно, что один из этих вызовов функции на самом деле является макросом, и в этом случае есть одно ключевое различие между do/while(0) и if(true), которое заключается в том, что первый позволяет continue и break.

2
ответ дан 29 November 2019 в 22:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: