Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
The switch statement in C/C++ has an interesing feature that all subsequent blocks will be executed if a condition is met
For example,
int a = 2;
int b = a;
switch(b)
{
case 1:cout<<1;
case 2:cout<<2;
case 3:cout<<3;
case 4:cout<<4;
};
The above code will output 234 unless I put a break statement in case 2.
In 3 years(quite small,yeah) of my C/C++ programming experience, I have never encountered a problem where I had to use switch without putting break statments in every case. But judging by the fact that this feature has been stuck for so long, there might be some utility of it.
Question: What are some clever uses of switch statement as to utilize the above mentioned feature in C/C++?
Probably one of the most interesting use cases I have seen would be Duff's Device the case where you extend a scope within a switch over multiple cases which would look something like this:
void send( int *to, const int *from, int count)
{
int n = (count + 7) / 8;
switch(count % 8)
{
case 0: do { *to = *from++; // <- Scope start
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while(--n > 0); // <- Scope end
}
}
This is usually used when you want to apply a similar action to a set of values. For instance, the following :
switch (event) {
case DEVICE_DISCONNECTED:
case CONNECTION_ERROR:
case CONNECTION_TIMEOUT:
transitionTo(disconnectedState);
break;
case CONNECTION_SUCCESS:
transitionTo(connectedState);
break;
}
is much more concise and readable in my opinion than :
switch (event) {
case DEVICE_DISCONNECTED:
transitionTo(disconnectedState);
break;
case CONNECTION_ERROR:
transitionTo(disconnectedState);
break;
case CONNECTION_TIMEOUT:
transitionTo(disconnectedState);
break;
// ...
}
In my current project, I have the following enumeration:
enum NodeType
{
SCALAR, COMPOSITE, ARRAY, RESTRICTED_ARRAY
};
Thus, quite a few node-processing routines use this pattern:
switch (nodeType)
{
case SCALAR:
processScalar();
break;
case COMPOSITE:
processComposite();
break;
case RESTRICTED_ARRAY:
if (!handleRestrictions())
return false;
// continue to next case
case ARRAY:
processArray();
break;
}
Note that it's almost necessary to always mark the lack-of-break as explicitly intended with a comment (like I did above) - future maintainers (including yourself in 3 months) will thank you.
I've often used a construct to parse command line arguments like this:
switch (argument) {
case arg_h:
case arg__help:
case arg_questionmark:
printf("Help\n");
break;
case arg_f:
case arg__file:
//...
}
where argument is an enum type.
Related
Reviewing some 3rd party C code I came across something like:
switch (state) {
case 0:
if (c=='A') { // open brace
// code...
break; // brace not closed!
case 1:
// code...
break;
} // close brace!
case 2:
// code...
break;
}
Which in the code I was reviewing appeared to be just a typo but I was surprised that it compiled with out error.
Why is this valid C?
What is the effect on the execution of this code compared to closing the brace at the expected place?
Is there any case where this could be of use?
Edit: In the example I looked at all breaks were present (as above) - but answer could also include behaviour if break absent in case 0 or 1.
Not only is it valid, similar structure has been used in real code, e.g., Duff's Device, which is an unrolled loop for copying a buffer:
send(to, from, count)
register short *to, *from;
register count;
{
register n = (count + 7) / 8;
switch(count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while(--n > 0);
}
}
Since a switch statement really just computes an address and jumps to it, it's easy to see why it can overlap with other control structures; the lines within other control structures have addresses that can be jump targets, too!
In the case you presented, imagine if there were no switch or breaks in your code. When you've finished executing the then portion of a if statement, you just keep going, so you'd fall through into the case 2:. Now, since you have the switch and break, it matters what break can break out of. According to the MSDN page, “The C break statement”,
The break statement terminates the execution of the nearest enclosing do, for, switch, or while statement in which it appears. Control passes to the statement that follows the terminated statement.
Since the nearest enclosing do, for, switch, or while statement is your switch (notice that if is not included in that list), then if you're inside the then block, you transfer to the outside of the switch statement. What's a bit more interesting, though, is what happens if you enter case 0, but c == 'A' is false. Then the if transfers control to just after the closing brace of the then block, and you start executing the code in case 2.
In C and C++ it is legal to jump into loops and if blocks so long as you don't jump over any variable declarations. You can check this answer for an example using goto, but I don't see why the same ideas wouldn't apply to switch blocks.
The semantics are different than if the } was above case 1 as you would expect.
This code actually says if state == 0 and c != 'A' then go to case 2 since that's where the closing brace of the if statement is. It then processes that code and hits the break statement at the end of the case 2 code.
#include<bits/stdc++.h>
using namespace std;
void show(int errorCause)
{
switch(errorCause)
{
case 1:
{
cout<<"in 1\n";
break;
}
case 2: break;
case 3:
{
cout<<"in 3\n";
break;
case 4:
{
cout<<"in 4\n";
case 5: cout<<"in 5\n";
break;
}
}
break;
default:
{
cout<<"in deafult\n";
break;
}
}
return;
}
int main()
{
show(5);
return 0;
}
I used this sample of code and I could not figure out its flow.According to me it should match the default condition as the errorCause does not match anything,but its output is:
in 5
I don't understand why it is not going to default condition?
Here is my build environment details:
compiler:
g++ version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
System:
Ubuntu 14.04(64-bit)
You pass 5, why should the switch statement not go into 'case 5'?
To make it clear: Remove all these curly braces inside the switch-block, none of them is necessary. The re-align and format the code, then it should be clear.
case/default labels for a switch statement may appear anywhere within that switch statement, except within a nested switch statement.
A famous example of this usage is Duff's device for unrolling loops:
void copy(unsigned char *to, const unsigned char *from, size_t count)
{
size_t n;
if (!count)
return;
n = (count + 7) / 8;
switch (count % 8) {
case 0:
do {
*to++ = *from++;
case 1:
*to++ = *from++;
case 2:
*to++ = *from++;
case 3:
*to++ = *from++;
case 4:
*to++ = *from++;
case 5:
*to++ = *from++;
case 6:
*to++ = *from++;
case 7:
*to++ = *from++;
case 1:
} while (--n > 0);
}
}
(adapted from the original).
At first glance, that doesn't make any sense (and it is somewhat redundant if you allow the compiler to unroll loops for you), but it illustrates that case labels can be placed more or less where you like within the switch statement.
First, don't write code like that. <g>
Second, the reason that it gets to case 5: is simply that there's a case 5: inside the switch statement. It doesn't matter that it's nested inside two levels of curly braces; it's just a label for the code to jump to. It doesn't have to be at the outer level of the switch statement.
It's because actually the switch statement evaluation is "relaxed", so the braces do not matter there. Only case matters, but you can jump right into the middle of a scope by the case (or even to the middle of a loop, see Duff's device).
because the value you passed is 5 , which exactly matches with the switch case parameter.
case 5: cout<<"in 5\n";
break;
if you want to get the default statement then modify the main function as shown below :
int main()
{
show(6);
return 0;
}
hope this helps.
Only last night I encountered the curious Duff's device for the first time. I've been doing some reading on it, and I don't think it's that daunting to understand. What I am curious about is the strange syntax (from Wikipedia):
register short *to, *from;
register int count;
{
register int n = (count + 7) / 8;
switch(count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while(--n > 0);
}
}
I was reading the C++ standard definition of a switch statement (please let me know if that's outdated, I'm not familiar with Open-Std.org). So far as I can understand case statements are just simplified jump statements for use by the switch statement.
The switch itself completely ignores the nested do-while, and the loop ignores the case statements. Since the switch jumps inside of the loop, the loop is executed. The switch is there to cover the remainder (from the division by 8), and the loop handles the portion that is evenly divisible. This all makes sense.
My question then is why the awkward syntax? It occurs to me that the loop could be written such that all of the case statements are contained within, yes? I see nothing in the standard that prohibits this behavior, and it compiles correctly under GCC 4.7, so is the following considered legal?
register short *to, *from;
register int count;
{
register int n = (count + 7) / 8;
switch (count <= 0 ? 8 : count % 8)
{
do
{
case 0: *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
default: ; // invalid count, suppress warning, etc.
} while(--n > 0);
}
}
To me this makes the intent of the code much clearer. Thanks for any feedback. ;)
Edit: As noted below, the original code was written for C and had implicit int for the count and n variables. Since I tagged it C++ I've modified that.
Edit 2: Modified the revised example code to account for invalid count values.
Looking at the C++11 Standard, the part of the code I think you're asking about would be allowed. Have you tried it?
The rule I see that's most applicable is:
Note: Usually, the substatement that is the subject of a switch is compound and case and default labels appear on the top-level statements contained within the (compound) substatement, but this is not required.
In fact, this means you could get rid of the braces around the do-while, and write
int n = (count + 7) / 8;
switch (count % 8) do
{
case 0: *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while(--n > 0);
However, this line is NOT valid C++:
register n = (count + 7) / 8;
C++ does not allow default-int, the type of a variable must be specified or inferred.
Oh here, fix the number of iterations without breaking formatting:
int n = 1 + count / 8;
switch (count % 8) do
{
*to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
case 0: ;
} while(--n > 0);
The code is certainly legal: There are no requirements at all about for blocks and/or loops. It is worth noting, though, that count == 0 isn't properly handled by the above loop. It is, however, properly handled by this one:
int count = atoi(ac == 1? "1": av[1]);
switch (count % 4)
{
case 0: while (0 < count) { std::cout << "0\n";
case 3: std::cout << "3\n";
case 2: std::cout << "2\n";
case 1: std::cout << "1\n";
count -= 4;
}
}
Putting the case 0 label inside the loop would also incorrectly execute the nested statements. Although I have seen Duff's device always using a do-while loop, it seems the above code is more natural to deal with the boundary condition.
Yes, it is legal. The labels of a switch statement is typically written at the same level as the switch statement. However, it is legal to write them inside compound statements, e.g. in the middle of a loop.
EDIT: There is no requirement that the body of the switch statement must start with a label, any code is legal. However, there is no way into it from the switch statement itself, so unless it is a loop, or a plain label, the code will be unreachable.
Another interesting thing with the swtich statement is that the braces are optional. However, in that case only one label is allowed:
switch (i)
case 5: printf("High five\n");
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Advantage of switch over if-else statement
Why the switch statement and not if-else?
The switch statement seems to be totally useless. Anything it can do can be done by if and else if link.
They probably even compile to the same code.
So why bother having it?
The break statements in switch drives me crazy and that label: format reminds me of goto.
This is for objective-c, c, C++. I am not sure if vb.net has switch statement, but even if it does I must have forgotten because I never use it.
They may well compile to the same code. But the intent is not necessarily to provide better compiled code so much as it is to provide better source code.
You can do while or for loops with if and goto as well but that doesn't make while and for useless. Would you rather have:
for (i = 0; i < 10; i++)
doSomethingWith (i);
or:
i = 0;
loop12:
if (! (i < 10))
goto skip12
doSomethingWith (i);
i++;
goto loop12
skip12:
if (color == WHITE)
{
}
else if (color == BLACK)
{
}
else if (color == GREY)
{
}
else if ((color == ORANGE) || (color == GREEN) || (color == BLUE))
{
}
else
{
}
vs
switch(color)
{
case WHITE:
break;
case BLACK:
break;
case GREY:
break;
case ORANGE:
case GREEN:
case BLUE:
break;
default:
break;
}
Isn't the latter more readable and requires lesser key strokes?
Apart from readability there's another unique use of switch-case: Duff's Device. This technique exploits the goto-ness of switch-case coupled with while.
void dsend(char* to, char* from, count) {
int n = (count + 7) / 8;
switch (count % 8) {
case 0: do {
*to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
}
Performance of switch is same as if and else if blocks in the worst case. It may be better. This has been discussed before: Advantage of switch over if-else statement
Pros:
Switch offers a better way to write program than if
Switch works faster than if because during execution compiler generates jump table to decide which case is satisfied rather than checking which case is satisfied!
Cons:
case can only have int or char constants or an expression that evaluates to one of these!
As a disclaimer, this is a homework problem. But it's one where the answer can't be found from our lecture notes and we're encouraged to find the answer through research (on the internet I presume). We're given the following code fragment, and asked for the technical name for this particular "peculiar" use of switch statement (this is in C++)
switch (x) {
case 0:
if ( m > n ) {
case 1:
for ( o = 0; o < 10; o += 1 ){
case 2:
p += 1;
}
}
}
where x, m, n, o, and p are int
I've answered all of the questions given about how the code operates under different conditions, but I can not find this mysterious technical name for this kind of switch statement. I've tried a few creative google searches, and read several pages about switch statement, but can't find mention of a case like this where if and for are nested within. Can anyone point me in the right direction??
A famous technique that is closely related to this is known as "Duff's Device". The Wikipedia page has a fairly detailed discussion that includes the following passage:
C's default fall-through in case
statements has long been one of its
most controversial features; Duff
observed that "This code forms some
sort of argument in that debate, but
I'm not sure whether it's for or
against."
I don't know if I've ever seen or heard of anything quite this twisted,
but I wonder if your prof wasn't thinking of Duff's device. The
original version was:
register n=(count+7)/8;
switch(count%8){
case 0: do{ *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
}while(--n>0);
}
(to pointed to a memory mapped IO register.) To quote Tom Duff (the
inventor), "I feel a combination of pride and revulsion at this
discovery," and "Many people (even bwk?) have said that the worst
feature of C is that switches don't break automatically before each case
label. This code forms some sort of argument in that debate, but I'm
not sure whether it's for or against."
Many, many years ago (about the time Tom Duff invented this), I came up
with something along the lines of:
switch ( category[*p] ) {
// ...
case CH_DOT:
if ( category[*(p + 1)] == CH_DIGIT )
case CH_DIGIT:
p = parseNumber( p );
else
case CH_PUNCT:
p = parsePunct( p );
break;
// ...
}
I never gave it a name, however, and never let it escape into production
code.