switch cases and one global variable for each case - c

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.

Related

Global variables in C on STM32

I'm working on a project where I need to use one variable declared in a certain file (say mylib.c) in the main function using 'extern'. All headers are included with guard words to avoid multiple inclusions.
The variable is a structure(defined in mylib.h) which members are only floats and integers.It's initialized at the beginning of the main function.
After entering the main's loop, and doing some work, some members that aren't concerned get random values.
So,I removed extern from the declaration in main, and instead placed it in the declaration in mylib.c. And it worked.
Sim808.h
#ifndef _SIM808_H
#define _SIM808_H
typedef struct{
uint8_t GPRS_Active;
float gsm_latitude;
float gsm_longitude;
}SIM808;
void sendCmd(const char cmd[]);
void sim808_init(void);
void parse_gsm_location(uint8_t* line);
#endif
Sim808.c
#include "sim808.h"
SIM808 sim808;
void parse_gsm_location(uint8_t* line)
{
uint8_t commas=0,index=0;
uint16_t err;
if((err=atoi((const char*)line+12))!=0)
{
printf("No coordinates received\n");
if(err==404 || err==601)
sim808.GPRS_Active=0;
return;
}
while (line[index]!= '\0' && index <50)
{
if(line[index]==',')
{
commas++;
switch (commas)
{
case 1:
sim808.gsm_longitude=atof((const char*)(line+index+1));
printf("Long:%f\n",sim808.gsm_longitude);
break;
case 2:
sim808.gsm_latitude=atof((const char*)(line +index+1));
printf("Longitude%f Latitude%f\n",sim808.gsm_longitude,sim808.gsm_latitude);
break;
case 3:
sscanf((const char*)(line+index+1),"%4d/%2d/%2d", (int*)&sim808.gsmDate.year,(int*)&sim808.gsmDate.month,
(int*)&sim808.gsmDate.day);
break;
case 4:
sscanf((const char*)(line+index+1),"%2d/%2d/%2d",
(int*)&sim808.gsmTime.hours,(int*)&sim808.gsmTime.minutes,(int*)&sim808.gsmTime.seconds);
break;
}
}
index++;
}
}
main.c
#include "sim808.h"
extern SIM808 sim808;
int main(void)
{
uint8_t response[150];
//init functions
while(1)
{
if(sim808.GPRS_Active==1)
{
sendCmd("AT+CIPGSMLOC=1,1\r\n");
HAL_UART_Receive(&huart4,response,2,60000);//max response time is 1 min
HAL_UART_Receive(&huart4,response,150,1000);//we dont need first 2 chars
parse_gsm_location(response);
memset((void*)response,0,150);
}
else
sim808_init();
}
}
As you can see,the member GPRS_Active can only receive 1 or 0 in my code.
Using printf, it turned to become 242 after the first iteration.
Can someone explain? Can this be a compiler bug?
Thanks.
The chance it is a compiler issue is really small. More likely is that your variable is modified by some part of your code. Try to avoid using global variables as they have the largest scope.
Do you use somewhere local variable with same name?
Have you checked map file or in debugger where it is placed?
You can use debugger feature datawatch where you break if data at certain address changes to help you track this issue.
When I use global variables, I do not declare them in the .h file to avoid issues of multiple inclusions. You can of course find some tricks to declare them in the .h, but I think it makes things so complicated. So try this:
In mylib.c:
int myGlobalVariable;
In main.c
extern int myGlobalVariable;
int main(void)
{
myGlobalVariable = 5;
}
If you still have issues, try to increase the size of your stack. If the stack is not big enough, it could be overwritten by other data.
If you use memset or memcpy in any of your code, make sure that the length parameter is correct. memset and memcpy are quite dangerous and you could easily write in some part of the memory that you don't really want.

Any jump with return instruction in C?

I have multiple locations in my code where I want to be able to jump to one specific location and return to where I was before.
A function calls provides that control flow but is not an option for me as I want the code I branch to to access a number of variables and passing all of them as arguments to the function call wouldn't be practical or efficient.
And the goto statement is only built to take a label, i.e. expected to be a one-way ticket.
Currently I am achieving what I need with the following:
void *return_addr;
int x,y;
...
return_addr=&&RETURN_0;
goto SOMEWHERE;
RETURN_0:
...
x+=1;
...
return_addr=&&RETURN_1;
goto SOMEWHERE;
RETURN_1:
...
SOMEWHERE:
y=x;
...
goto *return_addr;
Is there something more elegant and less cumbersome?
Is there something more elegant and less cumbersome?
You are obviously using GCC, as the computed goto statement is a GCC extension. With GCC we can use a nested function and access local variables without needing to pass them as arguments:
{
int x, y;
void SOMEWHERE()
{
y = x;
//...
}
//...
SOMEWHERE();
//...
x += 1;
//...
SOMEWHERE();
//...
}
Let's have the variables collected in a structure:
struct data_t {
int a;
int b;
/* and so on */
int x;
int y;
};
Let's have the repeated code defined in a function:
void func(struct data_t* data) {
data->y = data->x;
/* and so on */
}
Let's have the function used:
struct data_t data = {1, 2, ..., 24, 25};
func(&data);
data.x += 1;
func(&data);
/* and so on */
C has setjmp() / longjmp(), which can support what you describe. Do not use them. Even more, however, do not rely on your current approach, which is not standard C, and which is terribly poor form.
What you describe is what functions are for. If you have a lot of data that you must share between the caller and callee, then either
record them in file-scope variables so that both functions can access them directly, or
create one or more complex data types (presumably structs) with which to hold and organize the data, and give the callee access by passing a pointer to such a struct.
A state machine can be written like this:
typedef enum { start, stop, state1, ... } state;
state s = start;
while (s != stop) {
switch (s) {
case start:
do_stuff; // lots of code
// computed goto
s = cond ? state23 : state45;
break;
...
Need a call stack?
state stack[42]; int sp=0;
...
do_stuff;
stack[sp++] = state33;
s = state45; // call
break;
case state33:
case state45:
do_processing; // some code
s = stack[--sp]; // ret
break;
You should only do this after you benchmark your time-critical code sections and find that the normal function call mechanism is indeed the bottleneck.

Is there any better implementation for this switch case construct?

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.

Coverity warns on default initialization of local variables

There is a coverity warning type: UNUSED_VALUE. This is defined by tool under "Code maintainability issues"
UNUSED_VALUE: When a variable is assigned a pointer value returned from a function call and is never used anywhere else in the source code, it can not only cause inefficient use of resources but can also result in undetermined behavior. This checker identifies all variables that are never used anywhere else in the program after a value is assigned to them.
This checker seems to be picking up some of the good programming practice also as a warning.
My question is that is there some better way to do the things? Or should such a warning be ignored (and reported to Coverity team for any possible improvements)?
Example 1: default iniailization of local variables
int func()
{
int retval = SUCCESS; //COVERITY says: Unused value (UNUSED_VALUE)assigned_value: Value SUCCESS is assigned to retval here, but that stored value is not used before it is overwritten
retval = recvMessage(); //COVERITY says: value_overwrite: Value SUCCESS is overwritten with value fromrecvMessage
....
}
Example 2: setting pointer to NULL after memory is freed
void func2()
{
char *p = NULL;
....
p = alloc_mem_wrapper();
... do something
free_mem_wrapper(p);
p = NULL; //Coverity says: Unused value (UNUSED_VALUE)assigned_pointer: Value NULL is assigned to p here, but that stored value is not used
... do rest of the job (p is not used again)
}
In my case, 90% of all the warnings are of above nature only!
Why not do it like this:
int retval = recvMessage();
and this
char * p = alloc_mem_wrapper();
(Mostly) if you do not know how to initialise a variable you probably do not needed (where you defined it).
All above suggestions are good, but still people do stumble on this error and see it as a problem. I guess people relate it to a violation of good practice because they think it will appear in following scenario
int status = -1;
char c = getch();
switch(c){
case 'w': {
status = walk();
}
break;
case 's': {
status = sit();
}
break;
}
printf("Status %d\n", status);
Above, it makes total sense to declare status on top and print it once the code in between has updated it. However, Coverity does not report it UNUSED_VALUE in this scenario. It actually complains on following code
int status = -1;
int steps = 0;
char c = getch();
switch(c){
case 'w': {
status = walk();
steps = get_steps();
status = (steps > 0)?status:-1;
}
break;
case 's': {
status = sit();
}
break;
}
printf("Status %d\n", status);
Above, steps can simply be a scope variable. Hence, the Coverity error has more to do with the scope than initialization.

optimizing/ better way of coding a function and using its return value

I have some 20 to 30 functions, i have to call wsse_authenticate, in ever function for, and this wsse_authenticate function returns a value based on that value i send the fault message, Is there any way i can improve this code, so that i just call the function wsse_authenticate(soap) in every function and the switch case be replaced by some better code, i want to make it much efficient, Pls give me some inputs
wsse_ret = (wsse_authenticate(soap));
if(wsse_ret)
{
switch(wsse_ret)
{
case 1: onvif_fault(soap,"ter:NoSecuritytoken","ter:Failed_wsse_Aunthentication");
case 2: onvif_fault(soap,"ter:InvalidUserName","ter:FailedAunthentication");
case 3: onvif_fault(soap,"ter:InvalidPassword","ter:FailedAunthentication");
}
}
From the above code, I see that you are calling same function for all the cases expect for the "failure message" passed as an argument to function onvif_fault. And also there is no break after each case statement which would not give you result as expected.
Explanation for using break statement:
Suppose ret value is 1, then all the three cases would be executed since there is break statement at the end. Which means onvif_fault will be called three times with different parameters which is not expected.
Solution for you question
You can create a table using structures in c which actually has the list of the faults.
This was you can replace your Switch statements with only one line of code.
EX:
typedef struct _fault_messages
{
char msg1[254];
char msg2[254];
} fault_messages;
fault_messages msg_table[3] = {
{"ter:NoSecuritytoken", "ter:Failed_wsse_Aunthentication"},
{"ter:error1", "ter:fault1"},
{"ter:error2", "ter:fault2"}
};
Now, your fault messages in the above table are mapped. You can optimize your code as mentioned below:
wsse_ret = (wsse_authenticate(soap));
if(wsse_ret)
{
onvif_fault(soap, msg_table[wsse_ret-1].msg1, msg_table[wsse_ret-1].msg2);
}
If I understood correctly - your main problem is that you don't want to repeat security checking code in each and every function from 30 function set :-)
If that is the case you can try to use such pattern:
#include <stdio.h>
#include <string.h>
int isUserPasswordValid(char * password) {
return strcmp(password, "MyBigPassword") == 0;
}
#define callFunctionWithAuthentication(password, secPayload, execPayload) \
do {\
if (!isUserPasswordValid(password)) {\
secPayload\
}\
else {\
execPayload\
}\
} while(0);
int myTestFunction(int x) {
return x;
}
int main(int argc,char* argv[]){
// bad password - executes only authentication
callFunctionWithAuthentication(
"randomPassword",
printf("oops - bad password - can't continue\n");,
int a = myTestFunction(10); printf("function returned %d\n",a);)
// good password - executes authentication AND code after
callFunctionWithAuthentication(
"MyBigPassword",
printf("oops - bad password - can't continue\n");,
int a = myTestFunction(10); printf("function returned %d\n",a);)
return 0;
}
Only drawback that you must replace the call of each 30 function into the call of callFunctionWithAuthentication. But this is one-time task. Further you must always call this macro instead of plain function.

Resources