Why does C++ require breaks in switch statements? [duplicate] - c++

This question already has answers here:
Switch statement fall-through...should it be allowed? [closed]
(12 answers)
Closed 7 years ago.
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?

This is for the favour of "falling throught" 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.

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.

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.

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."

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.

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.:)

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.

Related

Can you use an OR in a switch?

Can you use an OR operator in a switch case? I was trying to remove case sensitivity from a user input check (so there may be a better way to do this altogether, I'm a beginner after all), and this of course resulted in doubling my switch case (not including the default case). Would it be better to use an if/else at this point, or is there a way to check for different conditions in a case?
My code, if it helps:
case 'Y':
case 'y':
cout << "Good, we will check later to ensure your opinion is unchanged." << endl;
break;
case 'N':
case 'n':
cout << "Open your window tonight, unlock the door, take sleep medication, and ignore any noises in your room." << endl;
break;
default:
cout << "Not an answer... think you can play games with me? I'll give you worse than the lemon haters, you'll be better off killing yourself before I take matters into my own hands." << endl;
If you do not plan to distinguish whether letters are lowercase or uppercase, then the best solution would be to "convert" your switch variable to lower/uppercase. By that you will get rid of unnecessary cases and save some time in future while implementing new ones.
Depending on your decision, you may choose std::tolower or std::toupper:
switch (std::tolower(x)) {
case 'y':
std::cout << "answer1" << std::endl;
break;
case 'n':
std::cout << "answer2" << std::endl;
break;
default:
std::cout << "answer3" << std::endl;
break;
}
Answering your question about usage of OR statement - it will not work well with char. All characters are defined with some integers (values from ASCII table), which means that e.g. y has the value 121, while Y has 89.
Let's take a look at expression case 'y' || 'Y': the value returned from 'y' || 'Y' would actually be 1. How is that possible? OR statement returns 1 if at least one of arguments is not 0 and 0 otherwise. This is how the value is calculated:
case 'y' || 'Y' => case 121 || 89 => case 1
Sadly, neither y nor Y is defined as 1 in ASCII, so switch will use default case with that input.
you can use it but it will not work, why? let me explain
when pass variable to switch() c++ will compare its value and type with each case, when you use "or" is a logical operator that means the result of the comparison will be a boolean value, check this example:
int main()
{
char input = 'R';
switch(input){
case 'R' || 'r' : // the 'or' opreator will return true wich is not equal to R
cout<<"wow!!!";
break;
default:
cout<<"meh";
}
return 0;
}
solution: you can use if/else statement
if(input=='Y' || input =='y'){
cout<<"Good, we will check later to ensure your opinion is unchanged." << endl;
}else if(input=='N' || input =='n'){
cout<<"Open your window tonight, unlock the door, take sleep medication, and ignore any noises in your room." << endl;
}else{
cout << "Not an answer... think you can play games with me? I'll give you worse than the lemon haters, you'll be better off killing yourself before I take matters into my own hands." << endl;
}
**or you can use tolower() to force the input to be lower case **
You can't use OR in a switch case, since it checks equality of the input and the case, so when using || evaluates to either true or false, which likely won't be equal to the input (for example, you check if a number, like 5, is equal to false). #Mohammed Khaled Gave a good explanation. What you can do is simply make an if/else chain (where you can use ||), or copy and paste the code from the switch cases.
int a = some_value;
switch(a) {
case 5:
do_something_1;
case 6:
do_something_1;
case 7:
do_something_2;
}

C++ Switch Cases

I was doing a quiz online based on the C++ switch statement. I came across a question and I have a fair understanding of how switch statements work but this one question made absolutely no sense to me. Can someone please explain?
Why is the answer D and not C?
Is Case 2: the default case or what?
This quiz can be found at: http://www.cprogramming.com/tutorial/quiz/quiz5.html
Here's how this code behaves.
x is equal to zero
so cout<<"Zero"; is executed.
Since there's no break; after it,
the second case is executed: cout<<"Hello World";
And since cout<<"something"; doesn't add a newline after printing, they're printed as a single word.
since there is no break; statements in each case, the code will fall-through from case 0: to case 2:.
In C++ a case will "fall-through" if there is no break statement:
int temperature = 20;
switch(temperature)
{
case 20:
cout << "it's nice and warm";
case 25:
cout << "it's a bit hot";
break;
case 30:
cout << "It's way too hot!";
break;
}
This will print out:
it's nice and warm AND it's a bit hot because there is no break statement.
Since, x=0. It matches the 2nd case i.e. (case 0: cout << "Zero"; ). But there is no break statement to break out of the switch statement, it executes next cases too. If you have other cases its gonna execute and stop only when it find break statement or reaches the end of the switch case.

Changing switch variable inside a case

In the following code:
int i = 0;
switch(i)
{
case 0:
cout << "In 0" << endl;
i = 1;
break;
case 1:
cout << "In 1" << endl;
break;
}
What will happen? Will it invoke undefined behavior?
No undefined behavior. But the value of i is only tested when the code reaches switch (i). So case 1: will be skipped (by the break; statement).
The switch keyword does not mean "run code whenever the value of i is 0 / 1". It means, check what i is RIGHT NOW and run code based on that. It doesn't care what happens to i in the future.
In fact, it's sometimes useful to do:
for( step = 0; !cancelled; ++step ) {
switch (step)
{
case 0:
//start processing;
break;
case 1:
// more processing;
break;
case 19:
// all done
return;
}
}
And changing the control variable inside a case block is extremely common when building a finite state machine (although not required, because you could set next_state inside the case, and do the assignment state = next_state afterward).
You break out of this switch statement after you set it to 1 which is defined behavior so it will never enter case 1.
There's no issue here. The expression in the switch condition is evaluated when it is reached. It doesn't have to be a variable and if it is the variable can be subsequently modified without any effect on the behaviour of the switch statement.
Your output would be :
"In 0"
even if you assign the value i = 1 it wont be reflected because switch does not operate in iteration, it is one time selection as break would make it go out of the switch statement.

Does case-switch work like this?

I came across a case-switch piece of code today and was a bit surprised to see how it worked. The code was:
switch (blah)
{
case a:
break;
case b:
break;
case c:
case d:
case e:
{
/* code here */
}
break;
default :
return;
}
To my surprise in the scenario where the variable was c, the path went inside the "code here" segment. I agree there is no break at the end of the c part of the case switch, but I would have imagined it to go through default instead. When you land at a case blah: line, doesn't it check if your current value matches the particular case and only then let you in the specific segment? Otherwise what's the point of having a case?
This is called case fall-through, and is a desirable behavior. It allows you to share code between cases.
An example of how to use case fall-through behavior:
switch(blah)
{
case a:
function1();
case b:
function2();
case c:
function3();
break;
default:
break;
}
If you enter the switch when blah == a, then you will execute function1(), function2(), and function3().
If you don't want to have this behavior, you can opt out of it by including break statements.
switch(blah)
{
case a:
function1();
break;
case b:
function2();
break;
case c:
function3();
break;
default:
break;
}
The way a switch statement works is that it will (more or less) execute a goto to jump to your case label, and keep running from that point. When the execution hits a break, it leaves the switch block.
That is the correct behavior, and it is referred to as "falling through". This lets you have multiple cases handled by the same code. In advanced situations, you may want to perform some code in one case, then fall through to another case.
Contrived example:
switch(command)
{
case CMD_SAVEAS:
{
this->PromptForFilename();
} // DO NOT BREAK, we still want to save
case CMD_SAVE:
{
this->Save();
} break;
case CMD_CLOSE:
{
this->Close();
} break;
default:
break;
}
This is called a fall-through.
It is exactly doing what you are seeing: several cases is going to execute same piece of code.
It is also convenient in doing extra processing for certain case, and some shared logic:
// psuedo code:
void stopServer() {
switch (serverStatus)
case STARTING:
{
extraCleanUpForStartingServer();
// fall-thru
}
case STARTED:
{
deallocateResources();
serverStatus = STOPPED;
break;
}
case STOPPING:
case STOPPED:
default:
// ignored
break;
}
This is a typical use of fall-through in switch-case. In case of STARTING and STARTED, we need to do deallocateResources and change the status to STOPPED, but STARTING need some extra cleanup. By the above way, you can clearly present the 'common logic' plus extra logic in STARTING.
STOPPED, STOPPING and default are similar, all of them fall thru to default logic (which is ignoring).
It is not always a good way to code like this but if it is well used it can present the logic better.
Luckily for us, C++ doesn't depend on your imagination :-)
Think of the switch labels as "goto" labels, and the switch(blah) simply "goes to" the corresponding label, and then the code just flows from there.
Actually the switch statement works the way you observed. It is designed so that you can combine several cases together until a break is encountered and it acts something like a sieve.
Here is a real-world example from one of my projects:
struct keystore_entry *new_keystore(p_rsd_t rsd, enum keystore_entry_type type, const void *value, size_t size) {
struct keystore_entry *e;
e = rsd_malloc(rsd, sizeof(struct keystore_entry));
if ( !e )
return NULL;
e->type = type;
switch (e->type) {
case KE_DOUBLE:
memcpy(&e->dblval, value, sizeof(double));
break;
case KE_INTEGER:
memcpy(&e->intval, value, sizeof(int));
break;
/* NOTICE HERE */
case KE_STRING:
if ( size == 0 ) {
/* calculate the size if it's zero */
size = strlen((const char *)value);
}
case KE_VOIDPTR:
e->ptr = rsd_malloc(rsd, size);
e->size = size;
memcpy(e->ptr, value, size);
break;
/* TO HERE */
default:
return NULL;
}
return e;
}
The code for KE_STRING and KE_VOIDPTR cases is identical except for the calculation of size in case of string.

Is It Possible To Do The Following In A Switch Statement - C++?

I am a programming student in my second OOP class, and I have a simple question that I have not been able to find the answer to on the internet, if it's out there, I apologize.
My question is this:
Is it possible have Boolean conditions in switch statements?
Example:
switch(userInputtedInt)
{
case >= someNum && <= someOtherNum
break;
// Is this possible?
}
No this is not possible in C++. Switch statements only support integers and characters (they will be replaced by their ASCII values) for matches. If you need a complex boolean condition then you should use an if / else block
As others have said you can't implement this directly as you are trying to do because C++ syntax doesn't allow it. But you can do this:
switch( userInputtedInt )
{
// case 0-3 inclusve
case 0 :
case 1 :
case 2 :
case 3 :
// do something for cases 0, 1, 2 & 3
break;
case 4 :
case 5 :
// do something for cases 4 & 5
break;
}
No, this is usually the purview of the if statement:
if ((userInputtedInt >= someNum) && (userInputtedInt <= someOtherNum)) { ... }
Of course, you can incorporate that into a switch statement:
switch (x) {
case 1:
// handle 1
break;
default:
if ((x >= 2) && (x <= 20)) { ... }
}
It's not possible directly -- a C or C++ switch statement requires that each case is a constant, not a Boolean expression. If you have evenly distributed ranges, you can often get the same effect using integer division though. e.g. if you have inputs from 1 to 100, and want to work with 90-100 as one group, 80-89 as another group, and so on, you can divide your input by 10, and each result will represent a range.
Or you can perhaps do this
switch((userInputtedInt >= someNum) && (userInputtedInt <= someOtherNum))
{
case true:
//do something
break;
case false:
//something else
break;
}
But that's just down-right terrible programming that could be handled with if-else statements.
This isn't possible. The closest you can some, if the values are reasonably close together is
switch(userInputtedInt)
{
case someNum:
case someNum+1:
// ...
case someOtherNum:
break;
}
C++ does not support that.
However, if you are not concerned with writing portable, standard code some compilers support this extended syntax:
switch(userInputtedInt)
{
case someNum...someOtherNum:
break;
}
Those values must be constant.
If you fancy the preprocessor you could write some kind of macro that auto-expands to the number of case statement required. However that would require a lengthly file with pretty much all case statements (ex: #define CASE0 case 0: #define CASE1 case 1: ...)
You shouldn't go there but it's fun to do...for fun! ;)
The standard does not allow for this:
6.4.2 The switch statement [stmt.switch]
[...] Any statement within the switch statement can be labeled with one or more case labels as follows:
case constant-expression :
where the constant-expression shall be an integral constant expression (5.19).
Some C++ compilers still support range notations today, 8 years after this question was originally asked. It surprised me.
I learned Pascal in 2012, Pascal do have range notations.
So it encouraged me to try the similar syntax in C++, then it worked unexpectedly fabulously.
The compiler on my laptop is g++ (GCC) 6.4.0 (from Cygwin project) std=c++17
There is a working example, which I wrote in hurry. repl.it
In addition, the source code is attached as follow:
#include <iostream>
using namespace std;
#define ok(x) cout << "It works in range(" << x << ")" << endl
#define awry cout << "It does\'t work." << endl
int main() {
/*bool a, b, c, d, e, f, g;
switch(true) {
case (a): break; These does not work any more...
case (b and c): break;
}*/
char ch1 = 'b';
switch(ch1) {
case 'a' ... 'f': ok("a..f"); break;
case 'g' ... 'z': ok("g..z"); break;
default: awry;
}
int int1 = 10;
switch(int1) {
case 1 ... 10: ok("1..10"); break;
case 11 ... 20: ok("11..20"); break;
default: awry;
}
return 0;
}