#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 делает в проводнике компилятора Godbolt2. Я знаю об этой проблеме, но если полученный вывод равен 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
вызывает арифметическое переполнение со знаком, которое имеет неопределенное поведение.