c-`while(1)`的替代方法,以简化分支

这个问题在这里已有答案:

  • 做{…} while(false)                                     24个答案
  • 如何避免“如果”连锁?                                     51个答案

有时,我使用break块来压平连续的break不成比例的情况。 它遵循这些原则。

而不是做:

// 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;
}

我对break末尾的隐式跳转感到有些恼火。我能否摆脱更精简的构造(即末尾没有break)?

我可以用变量(或寄存器?)交易最后的break。 这并不完全精简或清晰。

int once = 1;
while (once--) {
  // process
  if (!success) break;
  // process
  if (!success) break;
  // process
  if (!success) break;
  // etc
}

for循环看起来会更好一些(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:

你们还知道/使用什么其他方法?

Philippe A. asked 2019-11-17T16:53:03Z
6个解决方案
146 votes

你们还知道/使用什么其他方法?

您可以将if循环封装在一个函数中(并在您拥有static循环的地方调用此函数):

static void process(void)
{
   // process
   if (!success) return;
   // process
   if (!success) return;
   // process
   if (!success) return;
   // process
}

任何中途编译器(例如,即使禁用优化的if)也可以内联static函数(如果调用一次)。 (当然,某些变量可能必须在process函数的词法范围内,在这种情况下,只需将它们作为函数的参数来提供即可)。

请注意,从上到下而不是水平地写代码(例如,您的示例嵌套if)称为duffing。 这里有一篇关于这个主题的好文章:

“从上到下读取代码”

同样,在Linux内核编码风格中,有针对水平代码的特定警告:

“如果您需要三个以上的缩进级别,那么无论如何都要搞砸了,应该修复程序”

ouah answered 2019-11-17T16:54:37Z
54 votes

下面的方法与循环操作非常相似,但是最后不需要计数器或break语句。

do
{
    // process
    if (!success) break;
    // process
    if (!success) break;
    // process
    if (!success) break;
    ...
    // No need for a break statement here
}
while(0);
Fiddling Bits answered 2019-11-17T16:53:27Z
38 votes

如果您安排每个生成success的条件块的主体是如下函数,或者可以将每个f2()简化为布尔表达式,例如:

success = f1() ; 
if( success ) 
{
  success = f2() ; 
  if( success ) 
  {
    success = f3() ; 
    if( success ) 
    {
      success = f4()
    }
  }
}

然后,您可以利用短路评估将其简化为单个布尔表达式:

success = f1() && 
          f2() && 
          f3() && 
          f4() ;

如果f1()返回false并且每次后续调用都相同,则不会调用f2()-在第一个&&操作数子表达式中,表达式评估中止以返回false。

Clifford answered 2019-11-17T16:55:17Z
25 votes

不清楚为什么需要嵌套或中断。 当序列在第一次失败时需要保释时,我会一直这样做:

// process

if (success) {
  // more process
}

if (success) {
  // still more process
}

if (success) {
  // even more process
}
Paul Roub answered 2019-11-17T16:55:44Z
3 votes

摆弄东西提供了一种通用的方法。 另一种常见的方法是使用单个状态变量/标志来获得相似的结果。

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
}
Cloud answered 2019-11-17T16:56:11Z
2 votes

另一种选择是使用简单的标志变量

bool okay = true;

if(okay &= success){
    // process
}

if(okay &= success){
    // process
}

if(okay &= success){
    // process
}
frogatto answered 2019-11-17T16:56:37Z
translate from https://stackoverflow.com:/questions/25145321/alternatives-to-while-1-to-simplify-branching