Подтвердить что ты не робот

Что делает "делать {...} while (0)" точно в коде ядра?

Возможные дубликаты:
Что нужно использовать во время (0), когда мы определяем макрос?
Почему иногда существуют бессмысленные операторы do/while и if/else в макросах C/С++?
C многострочный макрос: do/while (0) vs scope block

Я видел много таких способов, как это, ранее я, хотя программист хотел легко выйти из блока кода. Зачем нам нужен цикл {...} while (0)? Мы пытаемся что-то сказать компилятору?

Например, в ядре 2.6.25 Linux включите /asm -ia64/system.h

/*
 * - clearing psr.i is implicitly serialized (visible by next insn)
 * - setting psr.i requires data serialization
 * - we need a stop-bit before reading PSR because we sometimes
 *   write a floating-point register right before reading the PSR
 *   and that writes to PSR.mfl
 */
#define __local_irq_save(x)         \
do {                    \
    ia64_stop();                \
    (x) = ia64_getreg(_IA64_REG_PSR);   \
    ia64_stop();                \
    ia64_rsm(IA64_PSR_I);           \
} while (0)
4b9b3361

Ответ 1

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

В вашем примере вам нужно написать

__local_irq_save(1);

а

__local_irq_save(1)

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

Ответ 2

Он позволяет здесь появиться код:

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

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

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

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

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

Ответ 3

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

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

if (/* some condition */)
  __local_irq_save(x); /* <- we can safely put `;` here */
else
  /* whatever */;

Ответ 4

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

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

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

Ответ 5

Похоже, он там только для обзора. Это похоже на:

if (true)
{
    // Do stuff.
}

изменить

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

Ответ 6

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

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

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

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

Итак, писатель макроса должен либо превратить его в настоящую функцию, либо обернуть конструкцию в один оператор, либо использовать расширение gnu.

Шаблон do .. while(0) - это подход "обернуть конструкцию".