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

Цель while (1); утверждение в C

Какую цель выполняет while(1);? Я знаю, что while(1) (без точки с запятой) петли бесконечно и подобен ситуации спин-блокировки. Однако я не вижу, где можно использовать while(1);?

Пример кода

if(!condition)
{ 
  while(1);
}

Примечание. Это не случай do - while() или простой while(1).

4b9b3361

Ответ 1

Обратите внимание, что все действительные выражения языка не соответствуют для. Они действительны для грамматики языка. Можно построить много подобных "бесполезных" утверждений, например if (1);. Я вижу такие утверждения, как конъюнкция условного (if, while и т.д.) И пустой оператор ; (который также является допустимым выражением, хотя явно не имеет никакой конкретной цели).

При этом я встретил while (1); в коде безопасности. Когда пользователь делает что-то очень плохо со встроенным устройством, может быть полезно заблокировать их от попыток чего-либо еще. С помощью while (1); мы можем безоговорочно заблокировать устройство, пока аккредитованный оператор не перезагрузит его вручную.

while(1); также может быть частью реализации паники ядра, хотя цикл for(;;) {} представляется более распространенным способом выражения бесконечного цикла, и может существовать непустое тело (например, для panic_blink()).

Ответ 2

Если вы копаете до сборки, (это проще понять с точки зрения встроенных систем, или если вы пытались запрограммировать загрузчик)

вы поймете, что цикл while - это всего лишь инструкция jmp... т.е.

(pseudo code: starting loop address)
add ax, bx
add ax, cx
cmp ax, dx
jz  (pseudo code: another address location)
jmp (pseudo code: starting loop address)

Давайте объясним, как это работает, процессор будет последовательно выполнять инструкции... независимо от того, что. Итак, как только он войдет в этот цикл, он добавит регистр bx в ax и сохранит в ax, добавит регистр cx в ax и сохранит его в ax, cmp ax, dx (это означает вычитание dx из ax) инструкция jz означает переход (другой адрес location), если установлен флаг нуля (который является битом в регистре флага, который будет установлен, если результат вышеуказанного вычитания равен нулю), затем jmp в адрес начального цикла (довольно прямолинейно) и переделайте все это.

Причина, по которой я беспокоил вас со всей этой сборкой, - показать вам, что это переведет на C в

int A,B,C,D;
// initialize to what ever;

while(true)
{
A = A + B;
A = A + C;

if((A-D)==0)
{break;}

}

// if((X-Y)==0){break;} is the 
// cmp ax, dx
// jz  (pseudo code: another address location)

Итак, представьте себе senario в сборке, если у вас только очень длинный список инструкций, которые не заканчиваются jmp (цикл while), чтобы повторить какой-то раздел или загрузить новую программу или сделать что-то... В конце концов процессор достигнет последней инструкции, а затем загрузит следующую команду, чтобы ничего не найти (он затем заморозит или утроит ошибку или что-то еще).

Именно поэтому, когда вы хотите, чтобы программа ничего не делала до запуска события, вам нужно использовать цикл while (1), чтобы процессор продолжал прыгать на свое место и не доходил до этого пустого адреса инструкции. Когда событие запускается, оно переходит к адресу инструкции обработчика события, выполняет его, очищает прерывание и возвращается к вашему while (1), цикл просто прыгает на свое место, ожидая дальнейших прерываний. Btw while (1) называется суперлоопом, если вы хотите больше узнать об этом... Просто для тех, кто безумно зудит, чтобы спорить и комментировать негативно на данный момент, это не учебник по сборке или лекция или что-то еще. Это простое объяснение на английском языке, которое настолько просто, насколько возможно, с учетом множества основных деталей, таких как указатели и стеки, а также многое другое и в некоторых случаях упрощение вещей, чтобы получить точную точку. Здесь никто не ищет точности документации, и я знаю, что этот код C не будет компилироваться подобным образом, но это только для демонстрации!

Ответ 3

Это помечено как C, но я начну с перспективы С++. В С++ 11 компилятор может оптимизировать while(1);.

Из стандартного проекта С++ 11 n3092, раздел 6.5, пункт 5 (выделенное мной):

Цикл, который за пределами инструкции for-init в случае оператора for for,
 - не вызывает вызовы функций ввода-вывода библиотеки и
 - не имеет доступа или изменения изменчивых объектов, и
 - не выполняет никаких операций синхронизации (1.10) или атомных операций (пункт 29)
можно предположить, что реализация завершается. [ Примечание. Это предназначено, чтобы разрешить преобразования компилятора, такие как удаление пустых циклов, даже если завершение не может быть доказано. - конец примечания]


Стандарт C11 имеет аналогичную запись, но с одним ключевым отличием. Из проекта стандарта C11 n1570 (акцент мой):

Оператор итерации , управляющее выражение которого не является постоянным выражением, 156) который не выполняет операций ввода/вывода, не получает доступ к неустойчивым объектам и не выполняет синхронизацию или атомарные операции в его теле, управляющее выражение или (в случае оператора for) его выражение-3 может быть реализовано завершением реализации. 157)
156) Пропущенное управляющее выражение заменяется ненулевой константой, которая является постоянным выражением.
157) Предполагается разрешить преобразования компилятора, такие как удаление пустых петель, даже если завершение невозможно доказать.


Это означает, что while(1); можно считать завершенным в С++ 11, но не в C11. Даже при этом примечание 157 (не обязательное) интерпретируется некоторыми поставщиками как позволяющее им удалить этот пустой цикл. Разница между while(1); в С++ 11 и C11 - это поведение по сравнению с undefined. Поскольку цикл пуст, его можно удалить в С++ 11. В C11 while(1); доказуемо не заканчивается, и это поведение undefined. Поскольку программист вывел UB, компилятор может свободно что-либо делать, включая удаление этого оскорбительного цикла.

Было проведено несколько обсуждений в stackoverflow для оптимизации компиляторов, удаляющих while(1);. Например, Разрешено ли компиляторам исключать бесконечные циклы?, Будет ли оптимизирован пустой цикл, используемый в качестве сна?, Оптимизация "" while (1);" в С++ 0x. Обратите внимание, что первые два были C-специфическими.

Ответ 4

Я предполагаю, что while(1); не связан с циклом do...

Единственная полуполезная реализация while(1);, которую я видел, - это цикл do-nothing, ожидающий прерывания; такой как родительский процесс, ожидающий SIGCHLD, указывающий, что дочерний процесс завершен. Родительский обработчик SIGCHLD, после завершения всех дочерних процессов, может завершить родительский поток.

Он делает трюк, но тратит много процессорного времени. Такое использование должно, возможно, выполнять какой-то сон, чтобы периодически отказываться от процессора.

Ответ 5

Использование встроенного программного обеспечения заключается в реализации программного обеспечения reset с помощью сторожевого таймера:

while (1);

или эквивалентно, но более безопасно, поскольку это делает цель более ясной:

do { /* nothing, let the dog bite */ } while (1);

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

Ответ 6

Одно место, где я видел while(1);, - это встроенное программирование.

В архитектуре использовался основной поток для отслеживания событий и рабочих потоков для их обработки. Был аппаратный сторожевой таймер (объяснение здесь), который будет выполнять мягкий reset модуля через определенный промежуток времени. В пределах цикла опроса основного потока он будет reset этим таймером. Если основной поток обнаружил неустранимую ошибку, while(1); будет использоваться для привязки основного потока, тем самым вызывая сторожевой таймер reset. Я считаю, что assert failure был реализован с помощью while(1);.

Ответ 7

Как говорили другие, это просто бесконечный цикл, который ничего не делает, полностью аналогичный

while (1) {
    /* Do nothing */
}

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

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

while (1)
    ;

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

Или используйте пустой составной оператор.

Ответ 8

while(1);

на самом деле очень полезно. Особенно, когда это программа, которая имеет какой-то код доступа или так, и вы хотите отключить использование программы для пользователя, потому что, например, он ввел неверный код доступа 3 раза. Использование while(1); остановит ход программы, и ничего не произойдет, пока программа не перезагрузится, главным образом из соображений безопасности.

Ответ 9

Это можно использовать для ожидания Interrupt. В основном вы инициализируете все, что вам нужно, и начинаете ждать чего-то. После этого вызывается и выполняется какая-то определенная функция, после чего она возвращается в состояние ожидания.

Это может быть нажата кнопка, щелчок мышью/перемещение, полученные данные и т.д.

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

Ответ 10

В программировании наборов микросхем AVR (с использованием языка программирования C) этот оператор часто используется, он играет роль, подобную циклу событий.

Предположим, что я хочу создать счетчик обратного отсчета, поэтому я могу использовать этот код для его реализации:

void interrupt0() {
   /* check if key pressed, count up the counter */
}

void main() {
    /* Common inits */
    /* Enable interrupt capability and register its routine */

    /* Event loop */
    while(1);
} 

Ответ 11

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

Ответ 12

Я думаю, что причина, по которой используется while(1);, заключается в том, что ранее в коде в этом потоке был установлен EventHandler или прерывание. Использование стандартного кода блокировки Thread Safe может быть довольно дорогостоящим (со временем), когда вы знаете, что ваш код будет "ждать" только очень короткое время. Поэтому вы можете настроить прерывание и "открутить", используя while(1);, который, хотя и является Busy Wait (не позволяет процессору Idle/service other threads), занимает очень мало циклов для настройки.

Таким образом, это "дешевая" спин-блокировка, в то время как ваш поток ожидает прерывания или события.