为什么C ++需要在switch语句中断?

时间:2015-04-28 09:44:47

标签: c++

在C ++中编写 switch 语句时,似乎必须在每个 case 之后包含 break 。否则,代码将继续进入下一个案例。

例如:

int x = 1;
switch (x)
{
    case 0:
        std::cout << "x is 0." << std::endl;
    case 1:
        std::cout << "x is 1." << std::endl;
    case 2:
        std::cout << "x is 2." << std::endl;
    default:
        std::cout << "x is neither 0, 1 nor 2." << std::endl;
}

将返回:

>> x is 1.
>> x is 2.

然而:

int x = 1;
switch (x)
{
    case 0:
        std::cout << "x is 0." << std::endl;
        break;
    case 1:
        std::cout << "x is 1." << std::endl;
        break;
    case 2:
        std::cout << "x is 2." << std::endl;
        break;
    default:
        std::cout << "x is neither 0, 1 nor 2." << std::endl;
        break;
}

将返回:

>> x is 1.

我的问题是:如果有必要为每个案例包含 break ,那么为什么C ++要求它明确地写入?为什么不在C ++中默认打开每个 case 之后的 switch 语句?有什么例子可能实际上不需要这种行为吗?

7 个答案:

答案 0 :(得分:8)

这是为了帮助&#34;堕落&#34;例:

switch (x)
{
    case 0:
    case 1:
        std::cout << "x is 0 or 1." << std::endl;
        break;
}

在此示例中,如果x为0或1,则执行case语句。

答案 1 :(得分:6)

这是因为rowEditing将被转换为汇编到switch val所在的特定地址的跳转,然后CPU将继续正常执行代码,因此获取下一个地址并继续,获取接着继续,case (some value):块在内存中的连续地址中,因此执行将会失败。 case将告诉CPU再次跳转,这次超出switch-case块不再执行break; es。

堕落可能是受益者,在一些较新的语言中你必须明确地说你想要它,在C和C ++中,堕落是隐含的。

来自我的机器的例子:

case

将成为

int i=1;
switch (i) {
case 1:
        i=5;
        break;
default:
        i=6;
}
return 0;

如果0x100000eeb: movl $0x1, -0x8(%rbp) ;int i=1; 0x100000ef2: xorl %eax, %eax 0x100000ef4: movb %al, %cl 0x100000ef6: testb %cl, %cl ;switch(i) 0x100000ef8: jne 0x100000f0f ;i is not 1 go to default: 0x100000efe: jmp 0x100000f03 ;i is 1 go to case 1: 0x100000f03: movl $0x5, -0x8(%rbp) ;case 1: i=5; 0x100000f0a: jmp 0x100000f16 ;break; 0x100000f0f: movl $0x6, -0x8(%rbp) ;default: i=6; 0x100000f16: movl $0x0, %eax ;first instruction after switch-case 之后没有跳转,那么cpu也会执行i=5;

答案 2 :(得分:3)

因为行为是从C继承的,而C则使用显式break代替。切换漏洞比那更有用,这就是为什么它被选为&#34;默认&#34;行为。

程序员时间更长,机器时间更少,因此设计最大潜在效率而非可读性更有意义。编译器的优化能力要低很多(在很多方面)。您可以查看Duff设备之类的内容,了解如何使用此行为。

答案 3 :(得分:1)

可能存在这样的情况,即您可能需要或想要获得两者的相同结果,或者可能是更多情况,那么您不需要休息。像这样:

switch (x)
{
case 1:
case 2:
case 3:
 some task
 break;
deafult:
 do some other task
 break;
}

上述代码最终与:

相同
switch (x) {
    case 0: // The case 1 code is shared here
    case 1:
        // code
        goto case 2;
    case 2:
        //some code here
        goto default;
    default:
        //some other code
        break;
}

来自K&amp; R

  

从一个案件落到另一个案件并不健全,容易发生   程序修改后解体。除了   单个计算的多个标签,应使用直通   谨慎地评论。

     

作为一个好的形式,在最后一个案例之后暂停(默认情况下)   这里)即使它在逻辑上是不必要的。有一天当另一个   案件最后添加,这一点防御性编程将会   救你。

正如小狗提到的那样,bahaviour是C语言固有的,所以引用书Expert C Programming

  

我们分析了Sun C编译器源代码   看看默认下降的频率   通过使用。太阳ANSI C   编译器前端有244个开关   声明,每个都有一个   平均7例。堕落   仅发生在所有这些案件中的3%。

     

换句话说,正常开关   行为是错误 97%的时间。   它不只是在编译器中 - 在...上   相反,在使用跌倒的地方   在这个分析中,它经常是   更频繁发生的情况   在编译器中比在其他软件中,   例如,在编译运算符时   可以有一个或两个   操作数:

switch (operator->num_of_operands) {
    case 2: process_operand( operator->operand_2);
              /* FALLTHRU */

    case 1: process_operand( operator->operand_1);
    break;
}
     

案件失败是如此广泛   被认为是有缺陷的   甚至是特别评论大会,   如上所示,告诉lint“这是   真的是其中3%的情况之一   希望失败。“

答案 4 :(得分:1)

首先,第一个程序的输出看起来像

x is 1.
x is 2.
x is neither 0, 1 nor 2.

C ++允许通过所有没有break语句的case标签传递控件。例如

char c;

std::cin >> c;

switch ( c )
{
case 'y': 
case 'Y': 
    std::cout << "Y was pressed" << std::endl;
    break;

case 'n':
case 'N':
    std::cout << "N was pressed" << std::endl;
    break;

default:
    std::cout << "Neither Y nor N was pressed" << std::endl;
    break;
}         

其他一些语言(例如C#)不允许这样做。然而,在任何情况下他们都需要休息声明。:)

答案 5 :(得分:0)

是的,每个切换案例后都必须包含breakreturn。 一个有用的例子,并非每个案例都有自动中断,当你得到键事件时,某些键应该做同样的事情:

switch (current_key) 
{
  case KEY_W:
  case KEY_UP:
  case KEY_SPACE:
       player->jump();
       break;
  case KEY_S:
  case KEY_DOWN:
  case KEY_SHIFT:
       player->cover();
       break;
  default:
       //Do something
       break; 
}

你可以为你编写一个代码函数:

const char* make_x_to_string(int x)
{
   switch (x)
   {
    case 0:
      return "x is zero";
    case 1:
      return "x is one";
    default:
      return "x is neither zero or one";
   }
}

然后简单地调用

cout << make_x_to_string(0) << endl;

您不需要break,因为return退出该功能。

答案 6 :(得分:0)

一个非常常见的例子:

switch (month) {
 case 2:
   if(isLeapYear)
    days = 29;  
   else
    days = 28;
    break;
  case 4:
  case 6:
  case 9:    // do the same thing
  case 11:
    days = 30;
     break;
  default:
    days = 31;
 }

从上面的示例中 - 您可以获得更清晰的代码,而且,您可以获得比在每种情况下隐式启用交换机所需的灵活性更多的灵活性。