替换`while(1)`以简化分支

时间:2014-08-05 17:56:16

标签: c

我不时使用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
}

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:

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

6 个答案:

答案 0 :(得分:146)

  

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

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

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

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

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

"Reading Code From Top to Bottom"

另外,在Linux kernel coding style中,对水平代码有一个特定的警告:

  

"如果你需要超过3个级别的缩进,你还是要搞砸了,并且应该修复你的程序"

答案 1 :(得分:54)

以下是一种非常类似于循环的方法,但最后不需要计数器或break语句。

do
{
    // process
    if (!success) break;
    // process
    if (!success) break;
    // process
    if (!success) break;
    ...
    // No need for a break statement here
}
while(0);

答案 2 :(得分:38)

如果您安排生成success的每个条件块的主体是如下函数,或者每个// process可以减少为布尔表达式,例如:

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

然后你可以将它减少为一个利用短路评估的布尔表达式:

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

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

答案 3 :(得分:25)

不清楚你为什么需要筑巢或休息。当序列需要在第一次失败时保释时,我会一直这样做:

// process

if (success) {
  // more process
}

if (success) {
  // still more process
}

if (success) {
  // even more process
}

答案 4 :(得分:3)

摆弄比特提供了一种常见的方法。另一种常见方法是使用单个状态变量/标志来实现类似的结果。

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
}

答案 5 :(得分:2)

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

bool okay = true;

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

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

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