Корректно ли идиома for(;;) для бесконечного цикла приписывается компилятору PDP-11 C?

Недавно я нашел эту статью, в которой утверждается, что идея предпочесть for(;;) вместо while(1) для бесконечного цикла возникла потому, что компилятор C, первоначально доступный на PDP-11, сгенерировал дополнительную машинную инструкцию для while(1).

Кстати, теперь даже предупреждения Visual C++ отдают предпочтение первому.

Насколько реалистична такая атрибуция for(;;) идиомы?


person sharptooth    schedule 28.11.2011    source источник
comment
В C нет такой вещи, как true...   -  person fredoverflow    schedule 28.11.2011
comment
Бедная статья. Он намеревается доказать, что обработка исключений ничего не стоит, а затем проверяет это утверждение с помощью кода, который не генерирует никаких исключений. У Borland есть гораздо лучшая статья на ту же тему.   -  person user207421    schedule 28.11.2011
comment
@FredOverflow: неверно. true — это макрос, определенный в stdbool.h (стандарт C99, раздел 7.16).   -  person JeremyP    schedule 28.11.2011
comment
@JeremyP: точнее было бы сказать, что в то время, о котором вы говорите, не было такой вещи, как true в C.   -  person Steve Jessop    schedule 28.11.2011
comment
Хорошо, ребята, мы все знаем обычную процедуру for(;;) против while(1). Но теперь мне искренне любопытно, может ли кто-нибудь придумать хорошую историческую цитату для фактоида PDP-11.   -  person hugomg    schedule 28.11.2011
comment
@EJP: Суть статьи в том, что добавление блоков try/catch практически не требует затрат для тех случаев, когда исключение не выдается, и это совершенно ясно изложено в статье (например, код перехвата (никогда не выполнялся). Решение было принято [от Microsoft] для реализации механизма исключений, который требует как можно более близкой к нулю стоимости при нормальном выполнении, но на самом деле довольно дорог, когда исключение действительно выдается.). Программа, которая генерирует исключения достаточно часто, чтобы беспокоиться о стоимости отправки этих исключений, использует исключения неправильным образом.   -  person Martin B    schedule 28.11.2011


Ответы (6)


Вот что выдает компилятор V7 Unix cc (используя SIMH и образ из TUHS):

$ cat>a.c
main(){
 while(1);
}
$ cat>b.c
main(){
 for(;;);
}
$ cc -S a.c
$ cc -S b.c

a.c (while) компилируется в:

.globl  _main
.text
_main:
~~main:
jsr     r5,csv
jbr     L1
L2:L4:tst       $1
jeq     L5
jbr     L4
L5:L3:jmp       cret
L1:jbr  L2
.globl
.data

В то время как b.c (for) становится:

.globl  _main
.text
_main:
~~main:
jsr     r5,csv
jbr     L1
L2:L4:jbr       L4
L5:L3:jmp       cret
L1:jbr  L2
.globl
.data

Так что, по крайней мере, верно то, что for(;;) компилируется с меньшим количеством инструкций, когда не используется оптимизация. Однако при компиляции с помощью -O обе программы создают точно одну и ту же сборку:

.globl  _main
.text
_main:
~~main:
jsr     r5,csv
L4:jbr  L4
.globl
.data

и когда я добавляю тело цикла printf("Hello");, программы остаются прежними.

Таким образом, вполне возможно, что эта идиома берет свое начало в машинном языке PDP-11, но к 1979 году разница уже была в значительной степени несущественной.

person Community    schedule 28.11.2011

Идиома for(;;) явно упоминается в оригинальном K&R. Мне достаточно авторства :)

person paulsm4    schedule 28.11.2011
comment
Имейте в виду, что K&R написал компилятор PDP-11, который был рабочим прототипом, который лег в основу книги… - person Potatoswatter; 28.11.2011
comment
В нем явно упоминается for(;;), но не PDP-11 или что-то еще о сгенерированном коде. Он просто говорит, что если условие опущено, оно всегда считается истинным. - person Jerry Coffin; 28.11.2011
comment
@Potatoswatter: R написал компилятор PDP-11, K - нет. В то время он был занят другими частями Unix. - person Steve Jessop; 28.11.2011
comment
-1. Появление for(;;) в K&R1 никоим образом не доказывает происхождение идиомы из машинного языка PDP-11. - person Fred Foo; 28.11.2011

Остерегайтесь определенной «разумной атрибуции», потому что они часто являются источником ложного мифа из-за отсутствия контекста. ОП пометил сообщение как C, так и C++.

K&R может быть полубогом в истории C, но определенно не может считаться авторитетом в C++. Кроме того, оптимизация компилятора может играть фундаментальную роль в C ++, но часто рассматривается как «оскорбительная» для системных программистов C (им нравится рассматривать C как «ассемблер с выражениями», а не как «язык высокого уровня»).

Сегодняшние компиляторы, скорее всего, будут создавать точно такой же код (это можно легко доказать), и использование того или другого в большей степени зависит от вкуса, чем от другого.

В этом смысле я предпочитаю for(;;), потому что легко могу прочитать его как "навсегда", а while(true) читать как "пока эта истина верна", что делает вас понять, как, если это может быть даже ложным ... . 2 мс мозгов потрачено впустую! (Но это личное мнение: я знаю многих людей, которые больше думают о for(;;), чем while(true))

Тем не менее, я также могу распознать их обоих как «живописные изображения» (не читая текст, просто глядя на то, как они выглядят через фотографическую память), указывающие на одну и ту же интеллектуальную концепцию (оставайтесь здесь, пока кто-нибудь не вышвырнет вас изнутри).

Насчет предупреждения MS, иногда оно спасает от плохо написанных выражений (типа true||a). Но явно злоупотребляют и не должны появляться из-за тривиальных выражений без операций внутри. Бесстрашный, компилятор MS выдает один и тот же машинный код в обоих случаях. Может быть, обратная связь с MS сделает их менее утомительными в отношении этого предупреждения в будущих выпусках.

person Emilio Garavaglia    schedule 28.11.2011
comment
Вы можете быть очень крутым и добавить #define ever (;;). Тогда вы можете написать буквально for ever. - person rodrigo; 28.11.2011
comment
@rodrigo: +1 за иронию. Но я не предлагаю. Если я вижу «навсегда», мне интересно, WTF «навсегда» может скрыться (особенно если он скрыт в 50 файлах глубины). 'for(;;)' - это именно то, чем является язык. Более безопасно для всех. - person Emilio Garavaglia; 28.11.2011
comment
@rodrigo: если на то пошло, ты можешь #define universe_exists (true). - person Steve Jessop; 28.11.2011
comment
Я пошутил, конечно. Любой здравомыслящий программист на C написал бы #define EVER (;;), но for EVER выглядит не очень [опять шутка]. - person rodrigo; 28.11.2011
comment
Просто #define forever и пусть будет for (;;) по нечетным неделям и while (1) по четным. - person u0b34a0f6ae; 28.11.2011
comment
@родриго молодец! Я удивлен, что никто не написал язык с ключевым словом this. - person Dmitry; 09.11.2016

Я не знаю, правда ли это, но претензия в статье разумна и реалистична. И for(;;) короче, чем while(1)

person Basile Starynkevitch    schedule 28.11.2011
comment
На самом деле это не так. Несмотря на то, что while(1) содержит больше символов, for(;;) требует двойного нажатия одной и той же кнопки, что может сильно замедлить набор текста. - person orlp; 28.11.2011
comment
Помимо того, что он короче для ввода, он позволяет избежать очень важного износа клавиш e и l, переключая их на ;. Это продлевает срок службы клавиатуры. - person Steve Jessop; 28.11.2011
comment
@Steve: Интересно! Мне нужно отправить все письма, которые я оставил. - person Potatoswatter; 28.11.2011
comment
К тому времени, когда вы прочитаете всю эту ветку, пытаясь решить, какой из них использовать, вы, вероятно, потратите больше времени, чем когда-либо выиграете, печатая более быстрый текст до конца своей жизни. - person mk12; 15.08.2012

Эм. Думаю, вы обнаружите, что K&R не писал компилятор PDP-11, поскольку PDP-11 был «машиной» (а не языком), которая уже имела свой собственный MACRO-ассемблер для своего собственного набора инструкций PDP-11.

K&R (по общему мнению) написали свой собственный компилятор 'C' в ... ну .. если бы это был MACRO, не так ли (поскольку это был единственный ассемблер с набором инструкций, доступный на PDP), а затем (по общему мнению) написал Unix на «C», поскольку они думали, что могут работать лучше, чем операционные системы DEC PDP-11 (RT-11 и RSTS-11) ... и они, вероятно, были правы!

person Richard    schedule 28.12.2012
comment
Если вы не хотите гадать, вы можете прочитать собственное описание Денниса Ритчи того, что произошло в Развитие языка C. - person Bo Persson; 29.12.2012

for(;;) является идиоматичным, поэтому будет здорово, если ваш код будут читать только опытные программисты на C. while(true) будет более понятен неопытным программистам и программистам, не работающим на C. Первый также полагается на некоторое неочевидное поведение, а именно на то, что пустое логическое выражение оценивается как истинное. По этой причине, если вы должны выбрать один, я бы посоветовал выбрать последний.

Однако я бы сказал, что практически во всех реальных случаях программист не хочет, чтобы код зацикливался вечно. Всегда есть причина, по которой вы можете захотеть завершить цикл, даже если пользователь просто нажал Ctrl-C. Никогда не нужен бесконечный цикл.

person JeremyP    schedule 28.11.2011
comment
Если вы программируете машину, которая в идеале никогда не останавливается, а C используется для программирования многих таких машин, то бесконечный цикл — идеальная модель. - person Potatoswatter; 28.11.2011
comment
То, что вы пишете, верно, но это совершенно не касается истории, о чем этот вопрос. - person Suma; 28.11.2011
comment
@Suma: Но строго определенный вопрос был не о программировании, а об истории C. - person JeremyP; 28.11.2011
comment
@Potatoswatter: такой машины нет. Всегда существует вероятность того, что машину необходимо отключить для обслуживания или выбросить. - person JeremyP; 28.11.2011
comment
Переход в автономный режим для обслуживания не обязательно означает выход из основного цикла. У такой машины уже есть универсальный механизм для аварийных ситуаций, который автоматически перезагружается, если внутренний сторожевой таймер не сброшен. Лучший способ установить обновление — активировать этот проверенный путь кода, используя ту же проверенную систему диспетчеризации команд, что и все остальное в основном цикле. - person Potatoswatter; 28.11.2011
comment
Кроме того, поскольку это C++, вы также можете выйти из цикла с помощью исключения, что более элегантно, чем добавление глобального условия is_exiting, и хорошо сочетается с тем, что я только что упомянул. - person Potatoswatter; 28.11.2011
comment
@Potatoswatter: выход из цикла по исключению - ужасная идея, если на самом деле не произошло исключительное условие. Обычное отключение не является исключительным состоянием. Гораздо лучше объявить условие выхода из цикла в том месте, где его легче всего найти, то есть в условии цикла, чем скрывать его где-то в теле цикла. - person JeremyP; 28.11.2011
comment
Для машины, которая запрограммирована никогда не останавливаться, остановка для установки обновления всегда является исключительным условием. Возврат из main будет определен как исключение и принудительная перезагрузка, как и любая другая разумная альтернатива. В любом случае… Я думаю, вы должны увидеть это, чтобы поверить в это. Это большой мир снаружи. - person Potatoswatter; 28.11.2011
comment
ОДНАКО часть - это религия, а не программирование. Из циклов также можно выйти с помощью break. Программисты знают, что, следовательно, for(;;) не означает бесконечность, просто она еще не известна на входе в цикл и не связана с оценкой выражения переменной состояния. - person Emilio Garavaglia; 28.11.2011
comment
Я предполагаю, что за это проголосовали так много, потому что это не касается вопроса. Впрочем, while(true) будет более понятно неопытным программистам — хороший и полезный момент. - person MickeyfAgain_BeforeExitOfSO; 14.11.2017