【问题标题】:where to put break in switch/case statement with blocks在带有块的 switch/case 语句中放置中断的位置
【发布时间】:2009-07-23 11:10:15
【问题描述】:

当我在 C++ 中的 case 代码块周围使用大括号来本地化变量时,我应该将 break 放在块内部还是外部?

case FOO:  // 'break' inside
  {
    int i;
    doStuff();
    break;
  }

case BAR: // 'break' outside
  {
    int i;
    doStuff();
  }
  break;

谢谢。

【问题讨论】:

  • 我觉得很有道理
  • 按原样说得通,但一个代码示例仍然会使其更清晰。

标签: c++ syntax


【解决方案1】:

这是风格问题。

我会将break 放在右大括号之外,以使其更具可读性。

【讨论】:

  • 同意。不同意(我认为它在里面更具可读性,但这只是我的风格:-0)
【解决方案2】:

你可以把它放在你喜欢的任何地方。确保在整个项目中保持一致。 (就我个人而言,我把它放在外面。)

【讨论】:

  • 我完全是为了一致性,但这也取决于代码流,如果需要更多控制是否中断,它可能会在内部更好地工作。
【解决方案3】:

它应该出现在之后。

例如:

switch(value)
{
   case 0:
   {
   // this ...
   // that ...
   // and the other ...
   }
   break;
}

编辑下方的文字

这主要是为了提高可读性和可维护性,这是一个示例。

switch (value)
{
   case 0:
    // Do this...
    // Do that...
    break;
   case 1:
    //and the other...
   break;
}

和

switch (value)
{
   case 0:
    // Do this...
    // Do that...
    if (ObjectWithinScope.Type == Fault)
    break;
   case 1:
    //and the other...
   break;
}

现在比较

switch (value)
{
   case 0:
   {
    // Do this...
    // Do that...
   }
   break;
   case 1:
    //and the other...
   break;
}

和

   switch (value)
    {
       case 0:
       {
        // Do this...
        // Do that...
        if (ObjectWithinScope.Type == Fault)
        break;
       }
       case 1:
       {
        //and the other...           
       }
       break;
    }

当您开始遇到嵌套 switch 语句的情况时,确实会变得非常混乱。

只是一个指针。

现在你们中的一些人仍然想知道我在说什么。这里是。一段遗留代码停止工作,没有人能弄清楚原因。这一切都归结为一段结构如下的代码:

   switch (value)
    {
       case 0:
       {
        // Do this...
        // Do that...
        if (ObjectWithinScope.Type == Fault)
        break;
       }
       case 1:
       {
        //and the other...           
       }
       break;
    }

这段代码花了很长时间才确定下来,但是在检查更改日志时,原来是这样的:

   switch (value)
    {
       case 0:
       {
        // Do this...
        // Do that...
        if (ObjectWithinScope.Type == Fault)
            // *** A line of code was here ***
        break;
       }
       case 1:
       {
        //and the other...           
       }
       break;
    }

诚然,原始代码与其自身不一致,但是通过在大括号内添加中断,代码在一行代码被意外删除时编译。如果中断在括号之外,则不会。

【讨论】:

  • 通过将它放在代码的块可读性和可维护性更清晰之后 - 我已经编辑了我的答案以显示一个恰当的例子。
【解决方案4】:

我通常将break 放在大括号内,如下所示:

switch (foo) {
    case bar: {
        int x = 5;
        printf("%d\n", x);
        break;
    }
    case baz: {
        // ...
        break;
    }
}

但是,既然这是我的规则,我可以随时打破它(不是双关语)。

【讨论】:

    【解决方案5】:

    每个人都同意,我们希望在 switch/case... 机制和在每种情况下执行的实际操作之间有一个清晰可辨的区别。

    因此,除非在每种情况下几乎什么都没有发生(简单的分配左右),我建议将switch 用作单纯的调度程序,并将“真实”的事情委托给辅助功能。这会自动解决 case-local 变量的问题,并且完全不需要大括号。

    switch( operation ) {
      case cnegation: r = -value; break;
      case cinversion: r = 1./r; break;
      case cfaculty: { 
        double r = value; 
        while( value != 1 ) 
          r *= --value; 
      }
      break;
    }
    

    应该变成

    switch( operation ) {
      case cnegation : r = negate (value) ; break;
      case cinversion: r = invert (value) ; break;
      case cfaculty  : r = faculty(value) ; break;
    }
    

    【讨论】:

      【解决方案6】:

      这是一个老问题,但我认为这里可以添加一些重要的东西:风格不仅对美学很重要,而且实际上可以在帮助防止由真实、易犯错误的人类编写的真实软件方面发挥作用.

      虽然break 语句的放置位置肯定是风格问题,而不是语言的要求,但我没有看到这里提到的一个约定,如果遵循它会更容易阅读、编写和查看switch 声明,同时确保不会出现任何意外失败。

      样式如下:

      switch(variable) {
          break; case 1 : statement;
          break; case 2 : {
             code in a block;
          }
          break; case 3 : other statement;
          /****/ case 4 : fall-through here on purpose.
          break; default: default behavior;
      }
      

      虽然您可能会争辩说这只是一种轻微的风格变化,但根据我的经验(在关键的嵌入式系统代码中使用这种风格已有 20 多年了)它更容易编写、审查和维护这种代码。最大的原因是因为它改变了概念思维模式。

      与其思考:“在这种情况下,做一堆我必须认真考虑的事情......是:“这要么是一个全新的条件,要么是前一个案例的失败;现在,在这种条件下,做一堆我可以认真思考的事情,然后继续前进。”

      【讨论】:

        【解决方案7】:

        这真的取决于你的代码的逻辑以及它如何使用大括号,但为了正确的答案,如果你把一个放在里面,试着把它们都放在里面。

        【讨论】:

          【解决方案8】:

          在我看来,您应该避免在 switch 语句中使用局部变量和块。此外,无论如何您都应该避免使用长的、复杂的甚至级联的 switch 语句。 但是没有规则没有例外......我更喜欢在块之后写break语句。

          【讨论】:

            【解决方案9】:

            只要您和您的团队始终如一地做同样的事情,这并不重要。即使那样,如果不同的团队成员做不同的事情,这也不是什么大问题。

            我个人更喜欢之后。原因是它在 switch 语句的机制(跳转、执行和退出)和大括号内的代码之间提供了一些分离,这些代码纯粹与案例的“执行”有关。

            例如:

            switch( value )
            {
                case 0:
                    {
                        // code here
                    }
                    break;
            
                default:
                    {
                        assert(!"unhandled value in switch");
                    }
                    break;
            }
            

            我只在需要局部变量的情况下使用 {},但如果我在任何情况下使用 {},我都会将它们放在所有情况下。

            我通常总是定义一个默认情况来断言是否有任何意外值。令人惊讶的是,其中一个断言经常触发以提醒您丢失的案例。

            【讨论】:

              【解决方案10】:

              我不喜欢在 switch 语句中放置任何类型的括号。就个人而言,如果它是一个复杂的操作,我喜欢把它放在一个函数中。没有什么比看到一个 switch 语句更烦人的了,其中每个“案例”之间有数百行代码,而且其中一些代码在各种情况下重复出现,这使得维护变得不可能。

              例如:

              switch(blah)
              {
               case 1:
                // do one thing
                break;
              
               case 2:
                doManyThings();
                break;
              
               default:  
                // something
                break;
              }
              

              【讨论】:

              • 在case语句中有一个局部变量并不意味着我有一个复杂的语句,里面有很多代码。
              【解决方案11】:

              这是风格问题,但我把它放在我理解的定义之后:

              switch (variable)
              {
                  case expression:
                      statement;
                      break;
                  default:
                      statement;
                      break;
              }
              

              where 语句可以是单个命令或块。中断与此语句或块是分开的。是的,我确实在默认值之后添加了一个中断,尽管它是多余的。我还总是在语句周围加上括号。太多次我添加了一条语句只是为了打破范围。我将 break 添加到默认值,因为我已将 default: 更改为 case expression: 并在其后添加了一些内容。防御性编码是您的朋友。

              但是,我只能通过 Microsoft 找到实际定义的文档:

              selection-statement:
                  switch ( expression ) statement
              
              labeled-statement:
                  case constant-expression : statement
                  default : statement
              

              这表明它应该在里面。

              但是,我认为从读者的角度来看,外部更清晰,但它肯定是主观的。

              【讨论】:

                【解决方案12】:

                由于标准不限制您为break 语句选择位置,您可以选择任何您喜欢的位置。我个人使用以下样式:

                 switch ( some_var ) {
                        case 1: {
                            // lot of code here
                        } break;
                        case 2: /* one call */ break;
                        case 3: /* one call */ break;
                        case 4: {
                            // lot of code here again
                        } break;
                    }
                

                【讨论】:

                  【解决方案13】:

                  对于每个案例只使用一个语句并且从不使用大括号的风格有很多话要说。例如:

                  开关(条件){ 默认值:foo();休息; 案例0:bar();休息; 案例一:baz();休息; }

                  使用这种风格,你的问题没有实际意义。

                  【讨论】:

                  • 为什么投反对票?这个问题纯粹是关于风格的,这是关于风格的答案?
                  【解决方案14】:

                  真正的答案:编译器不在乎。这是一个偏好问题。

                  我把它们放在里面,比如google style guide。

                  如果使用大括号,我希望左大括号与右大括号位于同一列(这与谷歌不同)。

                  switch (var) {
                    case 0: 
                    {  
                      ...      
                      break;
                    }
                    case 1: 
                    {
                      ...
                      break;
                    }
                    default: 
                      assert(false);
                  }
                  

                  【讨论】:

                    【解决方案15】:

                    我的看法...请参阅下面的示例。

                    缩进开关的所有大小写,并在关键字switch 下加上开关的右括号,就像在if 语句中所做的那样。在需要时,每个case 语句的相同规则:在case 语句之后的半列之后打开括号并在关键字case 下关闭它们,然后缩进每个case 语句的内容,包括关键字break。

                    保持一致(缩进和括号放置)和简短(每个 case 语句不超过 5-10 行代码。复杂的项目失败了,因为缩进严重的 switch 语句中包含太多代码。

                        switch (number) {
                    
                            case 1:
                                logFileStderr(VERBOSE, "MESSAGE: switch without brackets...\n");
                                break;
                    
                            case 2: {
                                logFileStderr(VERBOSE, "MESSAGE: switch with brackets...\n");
                                break;
                            }
                    
                            default:
                                logFileStderr(VERBOSE, "WARNING: Unknown option...\n");
                                break;
                        }
                    

                    【讨论】:

                      猜你喜欢
                      • 2016-01-18
                      • 1970-01-01
                      • 1970-01-01
                      • 2022-06-22
                      • 2019-07-09
                      • 1970-01-01
                      • 2013-09-24
                      • 2011-07-24
                      • 1970-01-01
                      相关资源
                      最近更新 更多