optimizing switch case code - c

I have below switch case in my code.
switch(condition)
case 'A' :
//Code part A
break;
case 'B' :
//Code part A
//Code part B
break;
case 'C' : //Some code
break;
code Part A is repeated in both case 'A' and case 'B'. I want to avoid duplication of code.
If we use fall though then we need to add an if condition for case B. Is this the only way for avoiding repetition of code?

If the order is not important, you can simply do:
switch (condition)
{
case 'B':
// Code part B
// no break
case 'A':
// Code part A
break;
...
}
A case 'B' will continue to execute through the case 'A' code because you didn't call a break.

Manipulating a switch statement to reduce duplication of code may work at first, but then you may add additional cases to the switch later, which may break that cleanness of that optimization. For example:
switch(condition)
case 'A' :
// Code part A
break;
case 'B' :
// Code part A
// Code part B
break;
case 'C' :
// Code part C
break;
case 'D' :
// Code part A
// Code part D
break;
Suddenly an optimization which seemed nice at the time, starts to become difficult to maintain, difficult to read and error prone.
Having already determined that there is common code, the cleanest response in my view is to write functions to perform the common code and call from each case. Going forward, this will continue to be maintainable.

Unfortunately, that's the only way, short of defining a function for partA.
You can reduce nesting by exiting the switch from inside the combined case label to make the code look a little more uniform:
switch (someValue) {
case 'A':
case 'B':
// Code part A
if (someValue == 'A') break;
// Code part B
break;
case 'C':
break;
}
This lets your part A and part B code have the same level of nesting.

Can "//Code part B" be executed before "//Code part A"? If so, you could just reorder them and let it fall through without an if condition.
I don't think there's much else to do, otherwise. One of the reasons for the creation of object-oriented languages was avoiding the duplication of code you have in imperative languages.

Related

My program jump over to case condition although the condition don't was true [duplicate]

I have a switch in which I check a property of some sort and if the check yields a specific value, I want to check another value, so I did something like this:
switch(property_A)
{
case NA:
if(value_0 == property_B)
property_A = value_a;
else if(value_1 == property_B)
property_A = value_b;
case value_0:
...
break;
case value_1:
...
break;
}
So, I know this solves my problem, but I don't know if this is a good idea or maybe should I go about this another way
# the NA case is something like a default case but not exactly, because it does tell me something, but not enough
It depends on what you want to do. If you get to the case NA, without the break keyword, the value_0 case will be executed after one of the two if branches is finished. So if that's the behaviour you want, it's OK not to use break, but I don't think that's what you wanted to do.
I suggest you simply move the if - else statement above the switch and remove the NA case. This way, you will first assign the correct data to property_A and then you can do whatever you want with it in the switch.
EDIT: As Jack Deeth points out, if you omitted the break statement on purpose, it's a good idea to add a comment that you did so.
Convention is to add a comment explicitly telling future-you and any other maintainers you intended the fallthough and you haven't accidentally omitted the break;.
switch(foo) {
case 1:
bar();
// fallthrough
case 2:
baz();
break;
case 3:
fizzbuzz();
}
If you're using C++17 or later you can use the [[fallthrough]] attribute to avoid a compiler warning:
switch(foo) {
case 1:
bar();
[[fallthrough]]
case 2:
baz();
break;
case 3:
fizzbuzz();
}
The additional information provided in the comments to the question indicate that what's wanted is not what's written in the question:
switch(property_A)
{
case NA:
if(value_0 == property_B)
property_A = value_a;
else if(value_1 == property_B)
property_A = value_b;
// here, we fallthrough into the code for value_0
// but you want to switch on the new value instead
case value_0:
...
break;
}
What you say you actually want is to set property_A if it was initially NA, then jump to the correct label. In that case, you'll need the assignment to be outside of the switch statement. You could do this with a goto at the end of the NA case, but I recommend you just deal with the NA before the switch:
if (property_A==NA)
property_A = (value_0 == property_B) ? value_a
: (value_1 == property_B) ? value_b
: NA;
switch (property_A) {
case value_0:
...
break;
case NA:
// we get here only if none of the replacement conditions
// matched, outside the 'case'
}

Last break in switch unnecessary?

I was musing over a switch statement I had written for 4 mutually exclusive cases. I inserted a break statement at the end of each case, because I didn't want to do the test again after one case or another had been successful.
Here's the question, though. What, if anything, does the last break do? If the test case 43 succeeds, the break terminates the case, but if there's no break, the default shouldn't run, and so there's no wasted test anyway.
Here's the code:
switch(telemetry) {
case(40):
printf("\nHouse Telemetry #%i \n", psc);
break;
case(41):
printf("\nNav Telemetry #%i \n", psc);
break;
case(42):
printf("\nDownhill Telemetry #%i \n", psc);
break;
case(43):
printf("\nRealTime Telemetry #%i \n", psc);
break; // what do I do?
default:
printf("\nCommand ID not recognized\n");
}
Perhaps one of you compiler gurus can advise me.
If you did not have the break; in case 43, it would fall through to the default case, and also execute the printf("\nCommand ID not recognized\n");.
Why do you think the default would not run? switch-case will continue execution until it encounters a break statement, and this includes the default section.
The break therefore is required for the desired behavior.
Putting a break; on the very last element of a switch-case (whether it is default or case) is optional, as it would stop execution that is coming to an end anyway.
I've encountered programmers who feel both ways about it: That there should not be an extra break at the very end of the block because it is not necessary, or that there should be one for consistency, and on the possibility that the sections get re-arranged in the future.
A switch statement is not a language construction that divides codes into separate cases. It is a computed “go to” statement: Based on the switch expression, it causes program control to jump to one of the labels.
Once that jump is completed, the switch does not exercise any further control over execution. It does not separate cases from one another or insert jumps or returns at the end of each case. Therefore, if you want control to leave the code for one case and not flow into the following code for another case, you must insert a break or other instruction that affects program control (such as return).
This characteristic of switch statements makes possible uses such as:
switch (letter)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
printf("Vowel.\n");
break;
default:
printf("Consonant.\n");
break;
}
Observe there are five case labels using one section of code. If the switch automatically separated them, the first four would be empty; nothing would be done for them when letter was a, e, i, or o.
Another example is where one case does some preparation work and then falls into another case, such as:
switch (operation)
{
case Subtract:
b = -b;
case Add:
result = a+b;
break;
case Multiply:
result = a*b;
break;
}
Here the Add case adds two numbers, and the Subtract case works by negating b and then continuing into the code for the Add case. This could not work if the switch automatically separated cases. (This is a simplified example, of course.)
The break keyword in each case indicates the end of a particular case. If we do not put the break in each case then even though the specific case is executed, the switch in C will continue to execute all the cases until the end is reached. This should not happen; hence we always have to put break keyword in each case. Break will terminate the case once it is executed and the control will fall out of the switch.

Execution of multiple cases within the same switch statement

I am looking through someone's C code, and discovered something I didn't even know was possible. Inside some of the cases, the switch variable is modified, with the intention that another case is executed after the break.
The switch is inside an interrupt handler, so it will get called repeatedly.
switch (variable)
{
case 1:
some_code();
variable = 3;
break;
case 2:
more_code();
variable = 5;
break;
case 3:
more_code();
variable = 5;
break;
case 4:
my_code();
break;
case 5:
final_code();
break;
}
The code seems to be working as the author intended.
Is this guaranteed behaviour in C? I always assumed that the break statement would cause execution to jump to directly after the switch statement. I wouldn't have expected it to continue testing every other case.
This is a common technique for state machine type code. But it doesn't jump automatically like you imagine. The switch statement has to be put inside a while loop. In this case, I imagine the loop would look something like:
while (!done) {
done = (variable == 5);
switch (variable) {
/*...*/
}
}
Alternatively, the switch statement could be inside a function body, and that function is called from a loop until the done condition is met.

What does switch do if there is no default case?

I have found a following piece of code:
switch(val){
case 0:
// some actions
break;
case 1:
// some actions
break;
case 2:
// some actions
break;
}
But it is not clear enough what will happen in the case of e.g val = 10?
I tried to test this code in a short program with incorrect value, and nothing had happen - program exited normally.
Can this code cause any potential error? Is there any guarantee that nothing will happen?
It will simply do nothing and not enter in any case.
It is recommended to have a default clause as the final clause in a switch statement. Programs like Lint will warn if you forget the default clause. And for information note that the default clause is required in MISRA-C.
EDIT:
I personally prefer it to be the final clause but I think the most important is for the final clause to be present. Why I prefer it to be the final clause is because of the Principle of least astonishment: people are used to see it as the final clause so I think it eases the program reading.
And just for information as I mentioned Lint and MISRA-C in my answer: PC-Lint / flexelint will not warn if default is present but not as the final clause and MISRA-C explicitly requires default to be present as the final clause.
That is why you should have a default case. It will handle cases other than those you typed.
What Happens in your case is that, it checks the case 0 and it doesn't match and checks case 1 and it also doesn't match and checks the case 2 and it again doesn't match. so it exits..
So it should be this way:
switch(val){
case 0:
// some actions
break;
case 1:
// some actions
break;
case 2:
// some actions
break;
default:
//some actions
break;
}
Another small point to note: it should case 0: not case 0;
If you use any other value from 0, 1, 2 (in this example) nothing will happen.
val will be compared with all values that are in cases and if it will not be equal to one of them, it just will jump to the next statement.

is it possible to do an OR in a case statement?

I want to do something like:
case someenumvalue || someotherenumvalue:
// do some stuff
break;
Is this legal in C?
The variable that I am doing a switch on is an enumerated list data struct.
You can rely on the fact that case statements will fall-through without a break:
case SOME_ENUM_VALUE: // fall-through
case SOME_OTHER_ENUM_VALUE:
doSomeStuff();
break;
You can also use this in a more complicated case, where both values require shared work, but one (or more) of them additionally requires specific work:
case SOME_ENUM_VALUE:
doSpecificStuff();
// fall-through to shared code
case SOME_OTHER_ENUM_VALUE:
doStuffForBothValues();
break;
Yes, you can simply skip the break in the first case to achieve the fall-through effect:
switch (expr) {
case someenumvalue: // no "break" here means fall-through semantic
case someotherenumvalue:
// do some stuff
break;
default:
// do some other stuff
break;
}
Many programmers get into the trap of fall-through inadvertently by forgetting to insert the break. This caused me some headaches in the past, especially in situations when I did not have access to a debugger.
you need:
case someenumvalue:
case someotherenumvalue :
do some stuff
break;
You can use fallthrough to get that effect:
case someenumvalue:
case someotherenumvalue :
do some stuff
break;
A case statement like a goto -- your program will execute everything after it (including other case statements) until you get to the end of the switch block or a break.
As others have specificied, yes you can logically OR things together by using a fall through:
case someenumvalue: //case somenumvalue
case someotherenumvalue : //or case someothernumvalue
do some stuff
break;
But to directly answer your question, yes you can do a logical, or bit-wise or on them as well (it's just a case for the result of the operation), just be careful that you're getting what you'd expect:
enum
{
somenumvalue1 = 0,
somenumvalue2 = 1,
somenumvalue3 = 2
};
int main()
{
int val = somenumvalue2; //this is 1
switch(val) {
case somenumvalue1: //the case for 0
printf("1 %d\n", mval);
break;
case somenumvalue2 || somenumvalue3: //the case for (1||2) == (1), NOT the
printf("2 %d\n", mval); //case for "1" or "2"
break;
case somenumvalue3: //the case for 2
printf("3 %d\n", mval);
break;
}
return 0;
}
If you choose to do the second implementation keep in mind that since you're ||'ing things, you'll either get a 1 or 0, and that's it, as the case.

Resources