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

#c #while-loop

Вопрос:

 #include <stdio.h>

int main() {
    int i = 10;
    while (i   != 0);
    printf("%d", i);
}
 

Выход: 1

Я не понимаю while петли.

Комментарии:

1. Какого результата вы ожидали?

2. while(i != 0); это то же самое, что while(i != 0) { /* void */ } …. так что цикл просто увеличивается i навсегда и навсегда … пока он не достигнет своего максимума, и программа не вызовет Неопределенное поведение … (или до тех пор, пока он не перейдет к негативам и не поднимется до самого конца 0 )

3. изменение знака произойдет только в том случае, если вы не используете типы данных без знака (т. е. uint i=10).

4. спасибо @pmg, я был немного сбит с толку. Теперь все в порядке.

5. @paul_schaefer , поэтому, если я использую uint, он станет нулевым после достижения максимального положительного значения

Ответ №1:

i увеличивается до тех int пор, пока переменная не насытится (32767, когда int имеет длину 16 бит), а затем начнет отсчет с -32,768 до нуля. Когда i становится равно нулю, цикл «время» останавливается. Из-за приращения после i , i будет один, когда цикл while будет завершен. Таким образом, вы получаете один результат, напечатанный на вашем выходе.

Редактировать: Длинное объяснение: При первом выполнении условия while будет проверено, не равно ли 10 0. После этой проверки i увеличивается до 11, следующая проверка 11 не равна нулю и i становится 12. Это продолжается до тех пор, пока вы не достигнете максимально возможного значения для int . Когда это максимальное значение увеличивается, вы получаете минимально возможное значение, но оно также не равно нулю. Таким образом, условие по-прежнему верно, но теперь у вас есть отрицательное число, и приращение отрицательного числа приведет к нулю. Поэтому через некоторое время, i становится равным нулю, и условие while является ложным, и так i как увеличивается после этой проверки, вы получите результат один.

Комментарии:

1. При увеличении этого максимального значения вы получаете минимально возможное значение .Я боюсь, что это поведение не гарантируется стандартом C , и компилятор C может определить, что i оно только увеличивается в цикле и начинается 10 , следовательно, цикл никогда не заканчивается. Это то, что gcc делает в проводнике компилятора Godbolt

2. Я знаю об этой проблеме, но если полученный вывод равен 1, как написано в вопросе, то есть две возможности: поведение такое, как я предполагал, или компилятор удаляет оператор while, потому что он пустой, и инициализирует i одним

3. Ваш ответ не намекает на то, что наблюдаемое поведение, для которого уместно ваше объяснение, является лишь возможностью, а не семантикой языка Си, которая оставляет этот конкретный случай неопределенным. Программа может вести себя по-разному по многим причинам, даже с одним и тем же компилятором ( -O0 -O2 например, vs)… не позволяйте оператору оставаться в неведении относительно неопределенного поведения.

Ответ №2:

Код имеет неопределенное поведение:

  • while цикл имеет пустое тело, состоящее из оператора null ; .
  • следовательно, цикл повторяется, не делая ничего, кроме побочного эффекта в тесте i != 0 .
  • i начинается с 10 того, что первый тест верен, i увеличивается до 11 , и цикл снова продолжается тестом… i увеличивается полностью INT_MAX , что меньше 32767 , но чаще 2147483647 , и увеличение i с этим значением имеет неопределенное поведение, потому что это вызывает переполнение арифметики со знаком. То, что произойдет потом, не определено, программа может остановиться, запустить бесконечный цикл, выключить свет… все возможно.
  • в вашей системе, i вероятно, просто получите значение INT_MIN , и никакого плохого побочного эффекта не произойдет.
  • цикл продолжается, увеличивая i все отрицательные значения…
  • пока i , наконец , не станет 0 , заставляя тест оценить значение false и прервать цикл после того, как побочный эффект произойдет в последний раз, оставив i значение 1 .
  • последний оператор printf("%d",i); печатается 1 без новой строки , что может помешать выходу на терминал в некоторых устаревших системах.

Таким образом, в зависимости от системы программа может:

  • распечатайте 1 и немедленно выйдите
  • печать 1 после паузы и выхода
  • беги вечно и ничего не печатай*
  • сбой с какой-то ошибкой
  • вызывают более или менее важный побочный эффект, такой как вызов инопланетян с Сириуса для вторжения на планету Земля…

(*) gcc -O2 компилирует опубликованный код в единую jmp инструкцию в проводнике компилятора Godbolt.

Комментарии:

1. @sj95126: пустое while() тело не является проблемой, увеличение i за пределами INT_MAX вызывает арифметическое переполнение со знаком, которое имеет неопределенное поведение.