0

做{...} while(0);

do{}while(0)的用法;在我的编码中使用,因为我不想使用 long if else 嵌套条件语句。我最终在失败时中断并退出循环,并保证我的函数至少会被遍历 1 次。

现在,问题出在代码警告工具上,我在使用do{...}while(0);时收到警告。

嵌套 if(){} else{}的使用可读性差,复杂度高。并让代码具有死代码。

如果我排除嵌套的 if(){} else{}do{} while(0); ,我们是否留下了一些其他方式来使代码具有可理解的逻辑可读性;

if(status_of_funcA_ok != funcA())
{ //failure}
else if (status_of_funcB_ok != funcB())
{//failure}
else if (status_of_funcC_ok != funcC())
else
{//Great}

do{
   if(status_of_funcA_ok != funcA())
   break;
   if (status_of_funcB_ok != funcB())
   break;
   if (status_of_funcC_ok != funcC())
   break;

  }while(0);
4

5 回答 5

5

do while{0}循环的完整逻辑移动到函数中,并将 替换breakreturn. 并调用函数,而不是循环。

  1. 你不必担心美丽。
  2. 编译器也不必抱怨do while{0}.

更重要的是,通过添加一些模块化,程序可能更具可读性。

无论如何,在这样做之前,最好检查一下您的编译器是否处于极其迂腐的模式,并且您可能希望将其关闭。这可能会消除警告。

ss。

PS:您似乎不需要该函数的返回值,但您可以通过它来获得哪个函数成功的线索。

于 2012-07-11T06:24:11.380 回答
2

我也在使用这种模式,对于那些想知道的人,这里有一个抽象的例子:

do   // while(0) for break
{ 
  state1 = 0;
  if (cond1())
  {
    if (cond2())
      break;
    state1 = opA();
  }

  if (cond3() || state1 && state1->cond4())
    break;
  ... 
  Triumph(state1, ...);
  // often here: return
}
Failure(state1, ...);

我认为这在以下情况下有效:

  • 你有一个很长的序列(比如说,>~六个条件)
  • 条件很复杂,并且您使用/建立重要状态,因此您无法将元素隔离为函数
  • 您处于对异常不友好的环境中,或者您的break-ing 代码路径实际上不是异常

你可以做些什么:

使警告静音。毕竟,这只是一个警告。而且我没有看到会被此警告捕获的“典型错误”(例如键入 0 而不是您的条件)。

[编辑] 现在,这很愚蠢。您收到警告的典型错误是例如while (a1!=a1)而不是while (a1!=a2).[/edit]

分解成函数,将状态移动到一个类,
这会将上面的代码转换为:

struct Garbler
{
  State1 state1;

  bool Step1()
  {
     state1 = 0;
     if (cond1())
     {
        if (cond2())
          return false;
        state1 = opA();
     }
     return true;
  }

  bool Step2()
  {
     return cond3() || state1 && state1->cond4();
  }
  .. 

  void Run()
  {
    if (Step1() && Step2() && ... && Step23())
      Triumph(state1, ...);
    else
      Failure(state1, ...);
  }
}

这可以说是可读性较差,更糟糕的是您将序列分开,这可能会导致一个非常有问题的类(其中成员可能只能按特定顺序调用)。

Scopeguards
这可能允许将休息时间转换为更容易接受的早期回报:

state1 = 0;
ScopeGuard gFailure = MakeGuard(&Failure, ByRef(state1), ...);
if (cond1())
{
   if (cond2())
     return;
   state1 = opA();
}

if (cond3() || state1 && state1->cond4())
  return;

// everything went ok, we can dismiss the scopeguard
gFailure.Dismiss();
Triumph(state1, ...);

它们可以用 C++0x 更优雅地编写,保留流程,但解决方案也不是那么灵活,例如,当Failure()不能轻松地将其隔离为单个函数时。

于 2012-07-11T06:26:16.690 回答
1

嵌套嵌套的 if-else 语句可能变得非常不可读,但我认为使用 do {..} while(0); 作为替代品会更糟。这是非常规的,任何其他阅读它的人都不会真正将它与 if-else 语句联系起来。

您可以做一些事情来使嵌套的 if-else 语句更具可读性。一些建议是:

  1. 优化您的逻辑 - 有时您可以在“重构”您的逻辑前取消很多 if 子句。对相同的项目进行分组。

  2. 使用 switch() - 与 if-else 语句相比,switch 通常更具可读性。您可以将枚举与每个案例相关联,并且可以切换它。

  3. 用函数封装复杂的逻辑

于 2012-07-11T05:39:47.813 回答
1

您可以使用和goto代替。不过,这不可读,也不是好的做法。我认为对于每种特定情况,都有更好的方法来避免深层 if/else 结构。例如,有时使用函数调用可以帮助:do {} while(0)break

例如,而不是:

if(status_of_funcA_ok != funcA())
{ //failure}
else if (status_of_funcB_ok != funcB())
{//failure}
else if (status_of_funcC_ok != funcC())
else
{//Great}

你可以写:

if (check_funcs() == 0) {
   great();
}

int check_funcs() {
   if (status_of_funcA_ok != funcA())
     return -1;
   if (if(status_of_funcB_ok != funcB())) 
     return -2;
   if (if(status_of_funcC_ok != funcC())) 
     return -3;
   return 0; /* great */
}

有时,您可以使用exit().

此外,在 c++ 中,您可以使用throw()and try/catch

try {
   /* */
  throw (this error);
   /* */
  throw (that error);
} catch (this error) {
} catch (that error) {
}
于 2012-07-11T05:15:20.927 回答
0

如果有更多条件要检查,请避免使用if{} else{},

最佳做法是将 if else 条件替换为switch case

于 2012-07-11T05:38:01.883 回答