Is there any better implementation for this switch case construct? - c

I'm working on an embedded system where a register hast to be accessed and after that to be incremented to achieve the result I'm looking for, since the machine is notifying and configured to react on my access and changing or not changing the flag. So the switch's argument has to be kept as it is, since it would otherwise change the behaving of the embedded system.
But there may occur a situation where I don't want to get any of the cases get invoked. But I still need to acces and increment the argument of the switch.
(More indepth I'm converting a sequence of analog values to digital values conversions step by step. The index is used to stay synchronized with the current conversion and relating it with the corresponding case to handle the figure correct. There may occur a state in which the index desynchronisizes to the current conversion so the sequence of conversions must be run through without any of the cases getting invoked (to prevent setting wrong data) untill the sequence is finished and the resynchroinisation can get performed)
The way I'm currently doing this is this:
switch (RunIndex++)/*RunIndex may only be accessed one time per execution
of this construct and has to be incremented in the same step. thats given.*/
{
if (RunIndexSyncedWithADCensured == false)
{
break;
}
case 0:
Case0RelatedData = SomeOperationsForCase0(RawData);
break;
case 1:
Case1RelatedData = SomeOperationsForCase1(RawData);
break;
case 2:
Case2RelatedData = SomeOperationsForCase2(RawData);
break;
default:
RunIndex = 0;
break;
}
This construct does the job but it looks like it is a bit controversial and I don't feel well by considering about committing this into productinal code.
So is there a better looking way to achieve the same, without the need of additional variables or assignements?
note:
Also it may be relevant, that this is in the first part of a interupt function consisting of 2 parts.
The first part handles what has to happen if() a conversion is finished. The second part, what has additional to be done if() this conversion also ended the sequence. So it is no option to simply return from the function without getting into the second part. and there is currently no loop structure where an if(...)break; may break out. (What is also the reason why I'm putting the if inside the switch scope, as it is at least by standard a valid way to break out.)

Firstly, the if() inside switch() will never be executed.
Consider the below code snippet:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i = 2;
switch(i) {
if (i == 2) {
printf("I M HERE\n");
}
case 1:
printf("1\n");
break;
case 2:
printf("2\n");
break;
default:
printf("default\n");
break;
}
return 0;
}
For your code: you expect the string I M HERE to be printed. But that is not the case.
The output for the above code snippet is:
2
No statements before case/default(switch constructs): is executed inside switch
Now to answer for
I don't want to get any of the cases get invoked. But I still need to acces and increment the argument of the switch
Just move the if() outside to the switch().
if (RunIndexSyncedWithADCensured) {
switch (RunIndex++) {
case 0:
Case0RelatedData = SomeOperationsForCase0(RawData);
break;
/* Other cases here */
default:
RunIndex = 0;
break;
}
} else
RunIndex++;

Why not save the value first and then increment it and use the saved value in the switch? By the way this also includes two accesses, first to read the value from RunIndex and the second to increment it.
int runIndex = (RunIndex++);
if (RunIndexSyncedWithADCensured )
{
switch (runIndex)/*RunIndex may only be accessed one time per execution
of this construct and has to be incremented in the same step. thats given.*/
{
case 0:
Case0RelatedData = SomeOperationsForCase0(RawData);
break;
case 1:
Case1RelatedData = SomeOperationsForCase1(RawData);
break;
case 2:
Case2RelatedData = SomeOperationsForCase2(RawData);
break;
default:
RunIndex = 0;
break;
}
}

Since you are using adjacent index numbers, you could make an array of function pointers to replace the switch. That's what the optimizer will turn the switch into anyhow. So instead of your obscure switch, you get this:
if (RunIndexSyncedWithADCensured)
{
SomeOperationsForCase[RunIndex](RawData);
}
RunIndex++;
if (RunIndex > MAX)
{
RunIndex = 0;
}
Completely unrelated to the switch statement design: in case RunIndex is a sensitive volatile variable such as some hardware register, then you shouldn't use it directly in any form of computations. Make a copy of it:
volatile int RunIndex;
...
int index = RunIndex; // read from RunIndex
if (RunIndexSyncedWithADCensured)
{
SomeOperationsForCase[index](RawData);
}
index++;
if (index > MAX)
{
index = 0;
}
RunIndex = index; // write to RunIndex
This is standard practice for all such volatile variables.

Related

MISRA demand a single point of exit for a function for a "lookup table" function

Misra standard demand a single point of exit for a function, but I have the following "conversion" code
typedef enum { CASE_A, CASE_B, CASE_C } my_enum_t;
int my_conv_funct(my_enum_t value)
{
switch(value)
{
case CASE_A:
return 0;
case CASE_B:
return 1;
case CASE_C:
return 2;
default:
break;
}
log_error("ERROR!!!!!");
assert(1==0);
}
Is this valid?
I need to convert it to a single return function?
And what is the best way of handling the default case?
this creates an unreachable code in theory (the error is to warn in case one add a value in the enum and not add a corresponding case)
This is an embedded system btw having those asserts create issues?
Thanks,
Nick
EDITED:
the default case should be never called if there are no errors (for example a programmer add another value in the enum and doesn't add a corresponding case
another options would be to remove the default at all but that violates another misra rule
typedef enum { CASE_A, CASE_B, CASE_C } my_enum_t;
int my_conv_funct(my_enum_t value)
{
switch(value)
{
case CASE_A:
return 0;
case CASE_B:
return 1;
case CASE_C:
return 2;
}
//should never reach this line
assert(1==0);
}
This will generate a warning if I compile and don't specify all the cases in the enum (I think)
Very simply:
int my_conv_funct(my_enum_t value)
{
int result = -1;
switch(value)
{
case CASE_A:
result = 0;
break;
case CASE_B:
result = 1;
break;
case CASE_C:
result = 2;
break;
default:
break;
}
if(result == -1)
{
log_error("ERROR!!!!!");
assert(1==0);
}
return result;
}
Is this valid?
It does not comply with the MISRA rule you described.
I need to convert it to a single return function?
To comply with the MISRA rule, yes.
And what is the best way of handling the default case?
We cannot judge what is "best" for your particular circumstances and use.
This is an embedded system btw having those asserts create issues?
The idea of an assertion is that it helps you find programming errors during development, but (in principle) it gets disabled via build options in code that is intended to be used in production. If that model is followed then the assertion itself probably does not create an issue, but the fact that the function does not return a value in the default case (if assertions are disabled) does. If the program must terminate in the event that the default case is exercised then it should call abort(), or some other function having that effect. Otherwise, it should return a sensible value in the default case.
I would probably write the function more like this:
int my_conv_funct(my_enum_t value)
{
switch(value)
{
case CASE_A:
case CASE_B:
case CASE_C:
break;
default:
log_error("ERROR!!!!!");
assert(0);
break;
}
return value;
}
There is now just one exit point from the function, and if it returns at all then it returns its argument (implicitly converted to type int).
First of all please check this answer: Best practice for compute the function return value. The MISRA-C rule is advisory and I recommend to make a permanent deviation against it. Personally I replace it with a rule such as:
"Multiple return statements in a function should be avoided unless they make the code more readable/maintainable."
The rationale to avoid returning from multiple places inside nested, complex code is sound, but far less so in clean and readable functions.
In your specific case though, I would perhaps have rewritten the function like this (MISRA compliant without ignoring the rule):
uint32_t my_conv_funct (my_enum_t value)
{
uint32_t result;
switch(value)
{
case CASE_A: result = 0; break;
case CASE_B: result = 1; break;
case CASE_C: result = 2; break;
default:
{
// error handling here
}
}
return result;
}
Alternatively (deviating from the rule):
uint32_t my_conv_funct (my_enum_t value)
{
static const uint32_t lut[] = { CASE_A, CASE_B, CASE_C };
for(size_t i=0; i<sizeof lut/sizeof *lut; i++)
{
if(lut[i] == value)
{
return i;
}
}
/* error handling */
return some_error_code;
}
This assuming that the amount of items isn't large, in which case a binary search might be more inefficient.
This in turn assuming that the enum constants don't correspond to 0, 1 and 2 in which case the whole function is nonsense.
The rationale for the MISRA C "single exit" Rule is because it is a requirement for the functional safety standards (eg IEC 61508 and ISO 26262).
It is also Advisory so can be disapplied if the circumstances so require.
My personal view is that a switch statement seldom needs multiple exits - it is easy to structure to avoid them... however there are situations (eg parameter validation) where it may make sense.
--
As an aside, use of assert() is non-compliant with MISRA C as it expands to abort() which is in breach of Rule 21.8 - this is also a very undesirable behaviour in an embedded system (and questionable in a hosted environment)...
--
See profile for affiliation.
The updated question has now been extended to include:
the default case should be never called if there are no errors (for example a programmer add another value in the enum and doesn't add a corresponding case
another options would be to remove the default at all but that violates another misra rule
I disagree...
The default is there as an error trapping mechanism - especially in real-time/embedded systems, data values may change unexpectedly (cosmic rays anyone) and it is a brave real-world engineer that does not protect against the unexpected.
How often has a default or else clause containing a comment /* Can never reach here */ actually been reached?

switch cases and one global variable for each case

I am dealing with a issue with switch cases.
Explanation of the program:
main(argc,argv).
argv leads to cases in a switch statement. Depending on the input, the according case will be entered and the corresponding function will be executed. -> Output is always a struct, with different content. More than one input (i.e. main.c case1 case3) is allowed-> executed both cases.
my problem is dealing with the passing of these data's and save it in a global variable, in order to print the collection. Inside of a case, I am passing the local results to the global variable, but after the break statement of the case, the global starts with NULL again and doesn't contain the info's of the executed case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "m.h"
output* print;
int main(int argc, char* argv[])
{
output_g* global; // global_struct
if(argc > 1)
{
global= create_global(argc-1); // allocation for global struct
for(int j = 0; j < argc; j++)
{
switch (atoi(argv[i]))
{
case 123:
{
output* print= 123();
if(print== NULL)
{
return 0;
}
global = fill_global(global ,print); // hands over the current struct to the global struct
delete(print); // free function
}
break;
case 456:
{
output* print= 456();
if(print== NULL)
{
return 0;
}
global = fill_global(global ,print); // hands over the current struct to the global struct
delete(print); // free function
}
break;
case 789:
{
lfnr++;
output_1* print_liste = 789();
if(print== NULL)
{
return 0;
}
global = fill_global(global ,print); // hands over the current struct to the global struct
delete(print); // free function
}
break;
default:
break;
}
print_global_struct(file,globale_liste);
delete_global(globale_liste);
}//End for-Schleife
}// End If
return 0;
}
a) If I understood you correctly, you don't understand the switch statement :)
A switch statement is similar to nested if statements.
so..
int x = 10;
switch (x)
case 1:
//does not happen, x is not 1
case 10:
//happens ...
after all that x is still 10, unless you changed it in the case statements explicitly. The cases just check to see IF x is a value, it does not SET a value. The same is true for any other variable in your code, the above code would not modify y either, unless you explicitly assign it inside a case it won't change.
b) it is best if you DO NOT declare locals in a case statement. They can become very wonky. The standard c++ rules work: variables declared inside {} pairs are scoped to inside that {} pair, so proper use of them will properly give the correct scope for each case. So it will work as expected if you apply braces. You should NOT declare a local in one case and use it in another, even if you can get it working (you can) it is error prone in that editing the code later can break things, the code can be confusing to read and work with, and its just generally a bad idea.
an example:
int main()
{
int x = 3;
switch(x)
{
case 1: int y;
case 2: y = 3;
case 3: y = 5;
cout << y << endl;
};
}
that compiled and ran for me, printing 5.
It worked fine -- I did not expect that, using g++ c17 options.
I still think it is a bad thing to do as far as reading and following the intent.
if you put {} around the int y statement, it does NOT compile anymore.
If you put breaks after the case 1 and case 2, it does NOT compile anymore.
so it is 'fragile' to being edited, at the very least, to do this.
c) run time won't lose anything. Ive had programs that ran for months on end. Being in a case has no effect on this either. The risk of losing variables is the 'ram' risk that all programs face... if a long running program is killed by power outage or malfunction etc you lose anything not saved to a file and have to start over. Long running programs should save their state periodically to protect against this.

Working with mathematical operations received as input

Let's say I'd like to receive two mathematical operations from a user (e.g. + - %) and calculate numbers accordingly. Let's also say I can use one if/else statement to determine precedence (and that all operations have different precedences).
I have several ideas in mind for implementation, and would like feedback regarding which is considered "better" coding (clearer, more efficient, etc.).
I could do something like this:
if (firstOperator >= secondOperator){
switch (firstOperator){
case '+':
switch (secondOperator)
// insert all 6 possible cases
case '-':
switch (secondOperator)
// insert all 5 possible cases
...
...
}
else{
// same idea as above
}
Or I could simply hard-code all options by creating one switch for every option of firstOperation, and nest a second switch in each of those cases for all possible secondOperation.
The two approaches are different, and I have one or two more. I would have thought that the first is more "correct" and elegant, but it actually results in more lines of code than the "brute-force" all-out second option.
I would love to hear any input regarding this kind of coding.
Note: I'm talking about only very basic C programming (i.e. without using other data structures like stacks, etc. Just the basic if/else, switch, loops, etc.
Here's how I would have done it, but it depends on your first and second operations being independently handled (which I think should be possible if what you are doing is an expression evaluator). In my example, I assume there is a queue holding the arguments that were parsed in the order they were parsed.
if (firstOperator >= secondOperator) {
handle(firstOperator);
handle(secondOperator);
} else {
// Assuming something like 1 + 2 * 3, with 1 2 3 in the queue:
//
// tmp = dequeueArg() makes the queue: 2 3
// handle('*') makes the queue: 6
// pushFront(tmp) makes the queue: 1 6
// handle('+') makes the queue: 7
//
int tmp = dequeueArg();
handle(secondOperator);
pushFront(tmp);
handle(firstOperator);
}
void handle(Op operator)
{
int x = dequeueArg();
int y = dequeueArg();
switch (operator) {
case '+': pushFront(x+y); break;
case '-': pushFront(x-y); break;
case '*': pushFront(x*y); break;
case '/': pushFront(x/y); break; // Maybe check for 0
case '%': pushFront(x%y); break; // Maybe check for 0
case '&': pushFront(x&y); break;
etc...
}
}
What I wrote here probably will not work as a general infix parser with precedence. It's more an example of how to not use O(N^2) nested case statements.

switch case in c, default before case

I was trying this :
#include<stdio.h>
int main() {
int i = 2;
switch(i) {
default:{
printf("Hi\n");}
case 1:
printf("Hi1\n");
case 2:
printf("Hi2\n");
}
}
output is "Hi2" as expected, however if i = 3,
#include<stdio.h>
int main() {
int i = 3;
switch(i) {
default:{
printf("Hi\n");}
case 1:
printf("Hi1\n");
case 2:
printf("Hi2\n");
}
}
Output is
"Hi"
"Hi1"
"Hi2"
How does program enter other cases which do not match? I know putting break in default would solve this.
Why this behavior? Is there anything mentioned in C specification for this?
In C (and many other languages) the cases are simply labels that get 'jumped' to. Once execution starts in a selected case, it flows just like normal. If you want execution to 'stop' at the end of a case 'block' you have to use the break statement (or some other flow control statement):
switch(i) {
default:{
printf("Hi\n");}
break;
case 1:
printf("Hi1\n");
break;
case 2:
printf("Hi2\n");
break;
}
}
For whatever it's worth, in my opinion this is was an unfortunate decision made by the language designers since falling through to the next case after execution one or more statements in a case are executed is very, very rarely desired. However, that's the way the language works.
C# addresses this by making it so falling out of a case is illegal - some sort of explicit flow control (a break or a goto) is required at the end of a sequence of of statements in a case (unless it's the last case in the switch).
This is because the code steps through each instruction unless explicitly stated not to.
In a switch() { }, you must be explicit.
Think about the instructions backed by this C. It would be a jump table. Without break, there would be no jump beneath each branch to go after the switch case.
Complementing #alex, try this.
#include<stdio.h>
int main() {
int i = 2;
switch(i) {
default:{
printf("Hi\n");}
case 2:
printf("Hi2\n");
case 1:
printf("Hi1\n");
}
}

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.

Resources