C11 уточняет ответ на этот вопрос, в проекте C11 стандарта раздел 6.8.5
итерационных заявления добавил следующий пункт:
итерационного о которой управляющее выражение не является постоянным выражение, 156), который не выполняет операции ввода/вывода, не выполняет доступ к энергозависимым объектам и не выполняет синхронизацию или атомную операцию в своем теле, контролируя выражение, или (в случае для оператора) его выражение-3, может быть принято путем завершения . 157)
и сноска 157
говорит:
Это предназначено, чтобы компилятор преобразования, такие как удаление пустых петель, даже если прекращение не может быть доказано.
Так что ваш конкретный пример:
while(1)
/* noop */;
не честная игра для оптимизации, поскольку управляющее выражение является константным выражением.
Бесконечные циклы, как UB
Так почему составители позволили оптимизировать на бесконечные циклы, за исключением приведенной выше, а Ханс Бем дает обоснование для создания бесконечных циклов неопределенное поведение в: N1528: Why undefined behavior for infinite loops?, следующая цитата дает хорошее чувство для выпуска вовлеченного:
Как N1509 правильно указывает, текущий проект по существу дает неопределенное поведение на бесконечные циклы в 6.8.5p6. Основная проблема для заключается в том, что он позволяет коду перемещаться по потенциальному циклу без конца. Например, предположим, что мы имеем следующие петли, , где граф и count2 являются глобальные переменные (или имели их адрес принято), а р является локальной переменной, адрес которого не был принят:
for (p = q; p != 0; p = p -> next) {
++count;
}
for (p = q; p != 0; p = p -> next) {
++count2;
}
Может эти два цикла объединяются и заменяются следующим циклом?
for (p = q; p != 0; p = p -> next) {
++count;
++count2;
}
Без специального разрешения в 6.8.5p6 для бесконечных циклов, эта будет запрещен: если первый цикл не завершается, поскольку Q указует на круговой список, оригинал никогда не пишет count2. Таким образом, можно запускать параллельно с другим потоком, который обращается или обновлений count2. Это уже не безопасно с преобразованной версией , которая делает доступ count2 несмотря на бесконечный цикл. Таким образом, трансформация потенциально представляет собой гонку данных.
В подобных случаях маловероятно, чтобы компилятор мог доказать завершение цикла; он должен был бы понять, что q указывает на ациклический список, который, как мне кажется, выходит за рамки большинства компиляторов большинства , и часто невозможно без всей программы информации.
C99
Поскольку C99 не имеет этого выкроить, мы будем смотреть на как если бы правило покрыты в разделе 5.1.2.3
, который в основном говорит о том, что компилятор имеет только эмулировать наблюдаемое поведение программы, требования заключаются в следующем:
Наименьшие требования к соответствующей реализации являются:
- В точках последовательности летучие объекты стабильны в том смысле, что предыдущие обращения завершены и последующие обращения еще не произошли.
- При завершении программы все данные, записанные в файлы, должны быть идентичны результату, который выполнил бы выполнение программы в соответствии с абстрактной семантикой .
- Динамика входных и выходных сигналов интерактивных устройств должна иметь место, как указано в 7.19.3. Цель этих требований состоит в том, чтобы как можно скорее появлялись небуферизованные или строковые буферизированные выходные данные , чтобы убедиться, что сообщения запроса действительно отображаются до программы, ожидающей ввода.
Буквальное толкование этого, казалось бы, позволяет реализации оптимизировать бесконечный цикл прочь. Мы, конечно, можно придумать сценарии, где оптимизируя прочь бесконечный цикл приведет к изменению наблюдаемого поведения:
while(1) ;
printf("hello world\n") ;
Многие утверждают, что осуществление прекращения процесса также наблюдаемое поведение, это положение берется в C Compilers Disprove Fermat’s Last Theorem:
компилятор дается большая свобода в том, как он реализует программу C, но его выход должен иметь тот же внешне видимое поведение, что программа будет иметь при интерпретированы «с абстрактной машины», который описан в стандарте , Многие знающие люди (включая меня) читают это, говоря, что поведение завершения программы не должно изменяться. Очевидно, что некоторые компиляторы не согласны или не считают, что это имеет значение. Тот факт, что разумные люди не согласны с интерпретацией, как представляется, указывает на то, что стандарт C является ошибочным.
Update
я как-то пропустил последующую деятельность в вышеуказанной статье, Compilers and Termination Revisited в котором говорится следующее о разделе 5.1.2.3
:
Второе требование является сложным один.Если речь идет о завершении программы, запущенной на абстрактной машине, то она неэффективно встречается, потому что наша программа не заканчивается. Если речь идет о завершении фактической программы, сгенерированной компилятором, то реализация C ошибочна, потому что данные, записанные в файлы (stdout - это файл), отличаются от данных, написанных абстрактной машиной. (Это чтение из-за Ганс Сет, я не смог дразнить эту тонкость из стандарта.)
Можно также сделать более слабый аргумент, что необходимость создания выкроить в C11, чтобы удалить пустую петлю подразумевает, что ранее это была недопустимая оптимизация.
Это относится также к бесконечным петлям goto?
Я считаю, что цель состоит в том, что это также относится и к бесконечным петлям goto. В C++ это явно случай, так как раздел 1.10
[intro.multithread] говорит:
Реализация может предположить, что любой поток, в конечном счете сделать один из следующих
- кончить,
- позвонить в библиотечную функцию ввода-вывода,
- получить доступ или изменить изменчивый объект, или
- выполнить операцию синхронизации или омическая операция.
, а затем намерение, выраженные в N1528
является то, что С и С ++ стандарт согласны:
Так как компилятор бэкенды, как правило, разделены между составителями C и C++, представляется наиболее важным, что WG14 и РГ21 согласны с тем, какое решение принято. Альтернативами было бы специальное обращение с двумя языками по внутреннему интерфейсу или отключение оптимизации при обработке кода C. Ничего не представляется желательным.
и в конце говорит:
WG21 рассматривает улучшенную формулировку, что делает лечение последовательным. Надеемся, что WG14 проведет все изменения.
В настоящее время стандарт C11 не содержит аналогичную формулировку в разделе 5.1.2.4
многопоточных казни и гонки данных но учитывая N1528
, кажется разумным предположить, компиляторы будут относиться к бесконечным Гото петлями, как неопределенное поведение в C и C++.
Примечание также см. US comment 38 here и N3196, который является бумагой, с которой это изменение было применено.
Ожидается ожидание, и демоны не будут долго ждать. Я называю такую конструкцию «мертвой» в средствах потока данных. Если оператор не изменяет никаких переменных и не содержит побочных эффектов, его можно устранить, оптимизируя компилятор. – osgx
Код после цикла не «недоступен», цикл может быть прерван сигналом, и в обработчике сигнала может быть «longjmp». – osgx
«Оптимизация бесконечных циклов» == «Как сделать бесконечные петли закончены быстрее» –