Подтвердить что ты не робот

"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");
4b9b3361

Ответ 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.