Альтернативы `while (1)` для упрощения ветвления
Время от времени я использую блок while(1)
, чтобы сгладить последовательность if..else
, выходящую из пропорции. Он идет по этим линиям.
Вместо этого:
// process
if (success) {
// process
if (success) {
//process
if (success) {
// etc
}
}
}
Я делаю:
while (1) {
// process
if (!success) break;
// process
if (!success) break;
// process
if (!success) break;
// etc
break;
}
Меня немного раздражает неявный прыжок в конце while
. Могу ли я уйти с более стройной конструкцией (т.е. Нет break
в конце)?
Я мог бы обменять окончательный break
на переменную (или зарегистрироваться?). Это не совсем четкое или четкое.
int once = 1;
while (once--) {
// process
if (!success) break;
// process
if (!success) break;
// process
if (!success) break;
// etc
}
А для цикла будет выглядеть немного лучше (C99):
for (int once = 1 ; once--; once) {
// process
if (!success) break;
// process
if (!success) break;
// process
if (!success) break;
// etc
}
Я думал об использовании корпуса коммутатора. Это выглядит не намного лучше, хотя это сработает.
switch (1) { default:
// process
if (!success) break;
// process
if (!success) break;
// process
if (!success) break;
// etc
}
В этом конкретном случае понятие метки кажется непобедимым.
// process
if (!success) goto end;
// process
if (!success) goto end;
// process
if (!success) goto end;
// etc
end:
Какой другой подход вы знаете/используете?
Ответы
Ответ 1
Ниже приведен метод, очень похожий на то, что вы делаете с циклами, но без необходимости в счетчике или инструкции break
в конце.
do
{
// process
if (!success) break;
// process
if (!success) break;
// process
if (!success) break;
...
// No need for a break statement here
}
while(0);
Ответ 2
Какой другой подход вы знаете/используете?
Вы можете инкапсулировать цикл while
в функцию (и вызвать эту функцию, где у вас был цикл while
):
static void process(void)
{
// process
if (!success) return;
// process
if (!success) return;
// process
if (!success) return;
// process
}
Любой наполовину достойный компилятор (например, даже gcc
с отключенными оптимизациями) встраивает функцию static
, если она вызывается один раз. (Конечно, некоторые переменные, возможно, должны быть в лексическом объеме функции process
, в этом случае просто укажите их как параметры функции).
Обратите внимание, что запись кода сверху вниз, а не горизонтально (например, ваш пример с вложенным if
) называется duffing. Здесь есть хорошая статья по этому вопросу:
"Чтение кода сверху вниз"
Кроме того, в стиле кодирования ядра Linux существует специальное предупреждение о горизонтальном коде:
", если вам нужно больше трех уровней отступов, вы все равно ввернуты и должны исправить вашу программу"
Ответ 3
Если вы согласны с тем, что тело каждого условного блока, генерирующего success
, является следующей функцией или каждый // process
в противном случае может быть сведен к булевскому выражению, например:
success = f1() ;
if( success )
{
success = f2() ;
if( success )
{
success = f3() ;
if( success )
{
success = f4()
}
}
}
Затем вы можете уменьшить это до одного булевского выражения, использующего оценку короткого замыкания:
success = f1() &&
f2() &&
f3() &&
f4() ;
Здесь f2()
не будет вызываться, если f1()
возвращает значение false, и то же самое для каждой последующей оценки выражения вызова прерывания в первом под-выражении операнда операнда &&
для возврата false.
Ответ 4
Непонятно, зачем вам нужно гнездиться или сломаться. Я делаю это все время, когда последовательность должна выполняться с первого раза:
// process
if (success) {
// more process
}
if (success) {
// still more process
}
if (success) {
// even more process
}
Ответ 5
Свернутые биты обеспечивают общий подход. Другим распространенным подходом является использование одного символа состояния/флага для достижения аналогичного результата.
bool bErr = false;
if (!bErr && success) {
// do something
} else {
bErr = true;
}
if (!bErr && success2) {
// do something
} else {
bErr = true;
}
if (bErr) {
// hanlde cleanup from errors
}
Ответ 6
Другим вариантом будет использование простой переменной флага
bool okay = true;
if(okay &= success){
// process
}
if(okay &= success){
// process
}
if(okay &= success){
// process
}