"break;" из инструкции "if"?
Вы можете вырваться из инструкции if или вызвать сбои? Я начинаю знакомиться с C, но это кажется спорным. Первое изображение из книги на C
( "Head First C" ), а фрагмент показывает код, написанный персоналом Harvard CS. Что на самом деле происходит и что-то связано со стандартами C?
перерывы не разрывают операторы if.
15 января 1990 года AT & T междугородняя телефонная система потерпела крах, и 60 000 человек потеряли свое телефонное обслуживание. Причина? Разработчик, работающий над кодом C, используемым на биржах, попытался использовать break
для выхода из инструкции if
. Но break
не выходят из if
s. Вместо этого программа пропустила весь раздел кода и представила ошибку, которая прерывала 70 миллионов телефонных звонков в течение девяти часов.
for (size = 0; size < HAY_MAX; size++)
{
// wait for hay until EOF
printf("\nhaystack[%d] = ", size);
int straw = GetInt();
if (straw == INT_MAX)
break;
// add hay to stack
haystack[size] = straw;
}
printf("\n");
Ответы
Ответ 1
break
взаимодействует исключительно с ближайшим замкнутым контуром или переключателем, будь то тип for
, while
или do .. while
. Его часто называют переопределением goto, так как все петли в C фактически могут быть преобразованы в набор условных gotos:
for (A; B; C) D;
// translates to
A;
goto test;
loop: D;
iter: C;
test: if (B) goto loop;
end:
while (B) D; // Simply doesn't have A or C
do { D; } while (B); // Omits initial goto test
continue; // goto iter;
break; // goto end;
Разница заключается в том, что continue
и break
взаимодействуют с виртуальными метками, автоматически помещенными компилятором. Это похоже на то, что делает return
, как вы знаете, оно всегда будет двигаться вперед в потоке программы. Переключатели немного сложнее, генерируя массивы меток и вычисляемых gotos, но сработал с ними разрыв.
Ошибка программирования, на которую указывает уведомление, является недопониманием break
как взаимодействующим с закрывающим блоком, а не замкнутым циклом. Рассмотрим:
for (A; B; C) {
D;
if (E) {
F;
if (G) break; // Incorrectly assumed to break if(E), breaks for()
H;
}
I;
}
J;
Кто-то подумал, что при таком фрагменте кода G
вызовет переход к I
, но он перейдет на J
. Назначенная функция вместо этого использовала бы if (!G) H;
.
Ответ 2
Это обычное использование оператора break
. Если оператор break
не был вложен в блок if
, цикл for
мог выполняться только один раз.
MSDN перечисляет это как пример для оператора break
.
Ответ 3
Я думаю, что вопрос немного нечеткий - например, его можно интерпретировать как вопрос о лучших практиках в циклах программирования с if
внутри. Итак, я постараюсь ответить на этот вопрос этой конкретной интерпретацией.
Если у вас есть if
внутри цикла, то в большинстве случаев вы хотели бы знать, как цикл закончился - был ли он "сломан" с помощью if
или закончился ли он "естественно"? Таким образом, ваш примерный код можно изменить следующим образом:
bool intMaxFound = false;
for (size = 0; size < HAY_MAX; size++)
{
// wait for hay until EOF
printf("\nhaystack[%d] = ", size);
int straw = GetInt();
if (straw == INT_MAX)
{intMaxFound = true; break;}
// add hay to stack
haystack[size] = straw;
}
if (intMaxFound)
{
// ... broken
}
else
{
// ... ended naturally
}
Проблема с этим кодом заключается в том, что оператор if
похоронен внутри тела цикла, и он требует определенных усилий, чтобы найти его и понять, что он делает. Более понятным (даже без оператора break
) будет:
bool intMaxFound = false;
for (size = 0; size < HAY_MAX && !intMaxFound; size++)
{
// wait for hay until EOF
printf("\nhaystack[%d] = ", size);
int straw = GetInt();
if (straw == INT_MAX)
{intMaxFound = true; continue;}
// add hay to stack
haystack[size] = straw;
}
if (intMaxFound)
{
// ... broken
}
else
{
// ... ended naturally
}
В этом случае вы можете четко видеть (просто глядя на заголовок цикла), что этот цикл может закончиться преждевременно. Если тело цикла представляет собой многостраничный текст, написанный кем-то другим, то вы бы поблагодарили его автора за сохранение вашего времени.
UPDATE:
Благодаря SO - он только что предложил уже ответивший question о сбое телефонной сети AT & T в 1990 году. Это о рискованном решении C создателям использовать одно зарезервированное слово break
для выхода из обоих циклов и switch
.
В любом случае эта интерпретация не вытекает из примера кода в исходном вопросе, поэтому я оставляю свой ответ так, как есть.
Ответ 4
Как уже упоминалось, break-statement работает только с помощью переключателей и циклов. Вот еще один способ добиться того, что задают. Я воспроизвожу
fooobar.com/info/28696/..., как никто другой не упомянул об этом. Это просто трюк, включающий цикл do-while.
do {
// do something
if (error) {
break;
}
// do something else
if (error) {
break;
}
// etc..
} while (0);
Хотя я бы предпочел использовать goto-statement.