6

When writing switch statements in C++, it seems necessary to include a break after every case. Otherwise, the code will continue to run into the next case.

For example:

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;
}

Will return:

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

However:

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;
}

Will return:

>> x is 1.

My question is: If it is necessary to include the break for every case, then why does C++ require it to be explicitly written at all? Why not just break the switch statement after every case by default in C++? Are there any examples when this behaviour may not in fact be desired?

Karnivaurus
  • 22,823
  • 57
  • 147
  • 247
  • 1
    What would you do if you wanted the same output for different `case`'s?, this is something that would be a pain to handle if it wasn't for this behaviour – EdChum Apr 28 '15 at 09:46
  • 3
    Because you may *want* to combine multiple cases – Panagiotis Kanavos Apr 28 '15 at 09:46
  • 2
    @PanagiotisKanavos: You could easily add something like explicit `continue` in that case. – Puppy Apr 28 '15 at 09:47
  • 1
    See also http://stackoverflow.com/questions/188461/switch-statement-fallthrough-should-it-be-allowed – Theodoros Chatzigiannakis Apr 28 '15 at 09:47
  • And that would be better? Not to mention, it would pollute the language with keywords that have very limited use. – Panagiotis Kanavos Apr 28 '15 at 09:47
  • It would be better, and `continue` is already a keyword... – Puppy Apr 28 '15 at 09:48
  • 4
    @Puppy so is `break`. Why one instead of the other? How do you weigh them? Personal preference is not an appropriate guide here – Panagiotis Kanavos Apr 28 '15 at 09:49
  • 1
    @PanagiotisKanavos: Because `break` is far more useful here than `continue`, so break-by-default is clearly the superior choice. – Puppy Apr 28 '15 at 09:50
  • My guess is that when designing, the fall-through by default made it possible to conveniently assign the case action to different values. However this forced everybody to put a break to end the case. You could consider the break to be a separator, but in the end I find it a nuisance. – stefaanv Apr 28 '15 at 09:56
  • 2
    Other languages usually allow multiple items in the case more explicitly, i.e. case 0, 1, 2: . I don't know how many bugs this construct in c++ is responsible for. I'm going to stick my neck out and say it's quite a big number. – Robinson Apr 28 '15 at 10:07

7 Answers7

10

This is for the favour of "falling through" cases:

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

In this example, the case statement is executed if x is either 0 or 1.

Robert Hacken
  • 3,878
  • 1
  • 13
  • 15
bytecode77
  • 14,163
  • 30
  • 110
  • 141
  • 2
    Even better, you can have some code in between `case 0` and `case 1` (e.g. do something specific to case 0, but then continue as like case 1 happened). – keltar Apr 28 '15 at 09:53
  • 2
    Did you intend that or is the missing break after case 0 a bug? This is why I don't like the construct. – Robinson Apr 28 '15 at 10:08
  • 3
    @Robinson that is the whole point, the `cout` gets executed for x=0 and x=1. No matter how it looks, it is still useful. – riodoro1 Apr 28 '15 at 10:11
  • 1
    I know. I'm just pointing out that a more explicit mechanism would improve the language and result in fewer bugs. – Robinson Apr 28 '15 at 10:16
  • @Robinson I personally don't like the syntax of switch..case, too. But once you define a "standard", you can't change it so easily... – bytecode77 Apr 28 '15 at 11:21
  • @keltar this is something extremely rare and hard-to-read. Lets admit that `switch` is just bad designed. – Vassilis Aug 31 '20 at 00:42
  • @Vassilis you're free to admit whatever you want. There are fallthrough attribute or even comments (which gcc understands) for that. – keltar Aug 31 '20 at 06:29
9

It is because the switch val will be translated to a jump in assembly to specific address where case (some value): is, then the CPU will continue executing code as normal, so fetch next address and go on, fetch next and go on, the case blocks are in consecutive addresses in memory so the execution will fall through. break; will tell the CPU to jump again, this time beyond the switch-case block not executing any more casees.

The fall through might be beneficiary, and in some newer languages You must explicitly say You want it, in C and C++ the fall through is implicit.

example from my machine:

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

will become

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

if there were no jump after i=5; then the cpu would execute the default: as well.

riodoro1
  • 1,246
  • 7
  • 14
4

Because the behaviour was inherited from C, which uses explicit break instead. Switch fallthrough was much more useful then and that's why it was chosen as the "default" behaviour.

There was just a lot more programmer time and a lot less machine time so designing for maximum potential efficiency instead of readability made a lot more sense. And compilers had a lot less power to optimize (in many respects). You can look at things like Duff's Device for examples of how this behaviour was used.

Puppy
  • 144,682
  • 38
  • 256
  • 465
2

There might be a situation when you may require or want to get the same result for the two or may be more cases then you dont need a break. Something like this:

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

The above code is eventually the same as:

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;
}

From the K&R

Falling through from one case to another is not robust, being prone to disintegration when the program is modified. With the exception of multiple labels for a single computation, fall-throughs should be used sparingly, and commented.

As a matter of good form, put a break after the last case (the default here) even though it's logically unnecessary. Some day when another case gets added at the end, this bit of defensive programming will save you.

As puppy has mentioned the bahaviour was inherent from the C language, so a quote from the book Expert C Programming

We analyzed the Sun C compiler sources to see how often the default fall through was used. The Sun ANSI C compiler front end has 244 switch statements, each of which has an average of seven cases. Fall through occurs in just 3% of all these cases.

In other words, the normal switch behavior is wrong 97% of the time. It's not just in a compiler - on the contrary, where fall through was used in this analysis it was often for situations that occur more frequently in a compiler than in other software, for instance, when compiling operators that can have either one or two operands:

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

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

Case fall through is so widely recognized as a defect that there's even a special comment convention, shown above, that tells lint "this is really one of those 3% of cases where fall through was desired."

Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
1

First of all the output of the first program looks like

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

C++ allows to pass the control through all case labels that has no break statement. For example

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;
}         

Some other languages as for example C# do not allow to do this. Nevertheless they require a break statement in any case.:)

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

A very common example:

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;
 }

From the above example - you get a much cleaner code, and also, you have more flexibility than you would have if the switch required to break out implicitly after every case.

Ayushi Jha
  • 4,003
  • 3
  • 26
  • 43
  • Although if the language specification had allowed `case 4, 6, 9, 11 :` it could have had a syntax for the above that avoided the undesirable default fall through behaviour. – Jack Aidley Feb 17 '16 at 11:07
0

Yes, it is necessary to include a break or a return after every switch case. An example where it is usefull, that not every case has an automatical break, is when you get key-events and certain keys should do the same thing:

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; 
}

and you may write a function for you code like this:

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";
   }
}

and then simply call

cout << make_x_to_string(0) << endl;

You don't need break there, because return exits the function.

danielspaniol
  • 2,228
  • 21
  • 38