【问题标题】:C - do{..} while(0); can be removed from code excluding usage nested if else?C - 做{..} while(0);可以从代码中删除,不包括使用嵌套 if else?
【发布时间】:2026-02-14 09:55:02
【问题描述】:

做{...} while(0);

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

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

时收到警告

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

如果我排除 nested 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);

【问题讨论】:

  • *.com/questions/10720465/… 对问题的解释不多,现在已经接近了。 :(
  • 你能举一个你的代码的一部分的具体例子吗?也许可以用不同的方式重写它
  • 编译器可以警告他们喜欢的任何东西;在所有情况下都避免所有警告是不切实际的。 大多数警告很重要,但如果您知道自己在做什么(即,在这种情况下,您实际上比编译器更了解),您可以忽略它们。
  • 我举了个例子!希望它会很容易理解。

标签: c++ c


【解决方案1】:

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

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

此外,通过添加一点模块化,程序可能更具可读性。

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

ss.

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

【讨论】:

    【解决方案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() 不能轻易地被隔离成一个函数时。

    【讨论】:

    • 一个非常精确和完整的答案。我的习惯(或多或少)是一样的。我的习惯一模一样。
    【解决方案3】:

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

    您可以采取一些措施来使嵌套的 if-else 语句更具可读性。一些建议是:

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

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

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

    【讨论】:

      【解决方案4】:

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

      例如,而不是:

      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()try/catch

      try {
         /* */
        throw (this error);
         /* */
        throw (that error);
      } catch (this error) {
      } catch (that error) {
      }
      

      【讨论】:

      • throw() 和 catch() 应仅用于特殊情况(例外)。将它们用作流控制结构是不好的做法。
      • 谢谢您的回复.. 我认为 goto/return 会是一个更好的选择,但是.. 愚蠢的讨厌工具也有这些东西作为警告。作为 multiple break,goto 的使用。 因为我使用 C,throw 和 catch 不适用,我可以使用子辅助函数指针,它将包裹每个条件,在我可以运行的循环中这些功能。但是对于或多或少 4 到 5 个条件检查的小功能,但是这种方法在嵌入式编程中是否可以接受是一个严重的疑问,因为我对行业非常陌生。
      • @bancsy:它们是原则上的流量控制结构,如果不控制流量,你还能如何使用它们?它们应该用来转义没有意义的代码路径,这是否会发生很多取决于您的情况。通常你可以有一个函数来检查会导致你的处理函数抛出的先决条件并返回一个布尔值,所以你可以在某种程度上选择退出异常。
      • @valdo:大多数较新的编译器版本不会编译带有 goto 的代码,这会导致 ctors/dtors 出现问题(就像其他一些情况一样)。
      【解决方案5】:

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

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

      【讨论】: