Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this strategy, to avoid global variables in C, right? [closed]

in my (personal) embedded project global variables are piling up. I need those variables to be acessible from the ISR (interrupt service routine) and/or from a menu system (so that they can be modified by the user) but at the same time I'd like to avoid having too many globals.

Since they can be grouped for modules I thought that I can encapsulate them in their own .c file, declared as static or static volatile , and expose to the outside world some functions to handle them.

Something along the line of:

in module1.c

#include module1.h

static volatile int module1_variable;

int getModule1Var(void){
    return module1_variable;
}

void setModule1Var(int i){
    //some code to disable interrupts for atomic operations
    module1_variable = i;
    //some other code to re-enable interrupts
    return;
}

module1.h would contain the function prototypes, structs and all the other elements for making the module work except for the static variable definition of course

in main.c

#include module1.h

void main(){
    //setting the variable value, could be done from a menu 
    setModule1Var(15);
    //remaining application code
}

void generic_ISR(){
    //trivial usage example
    doSomething(getModule1Var());
    return;
}

This scheme would naturally be extended to the other modules.

Now my questions are:
is this a good approach? Is it the same to simply have a bunch of globals? Any major drawbacks?

I also thought I could use some sort of mix like still having the global variables to allow direct manipulation by the ISR (since function calls from the ISR are sometimes frown upon) and the functions in every other case. Would this be better?

like image 854
zakkos Avatar asked Apr 19 '17 13:04

zakkos


People also ask

Should you avoid global variables in C?

Master C and Embedded C Programming- Learn as you go Non-const global variables are evil because their value can be changed by any function. Using global variables reduces the modularity and flexibility of the program. It is suggested not to use global variables in the program.

How can we avoid global variables?

Example 2: Creating a local variable with local scope within a function and also creating a local variable with the same name as the previous local variable within another function. This ensures there are no conflicts in multiple variables with the same name defined in the script.

Why you should avoid global variables?

Global variables can be altered by any part of the code, making it difficult to remember or reason about every possible use. A global variable can have no access control. It can not be limited to some parts of the program. Using global variables causes very tight coupling of code.

What can I use instead of global variables in C?

In a scenario, where you need one central global point of access across the codebase, singletons are a good alternative for global variables. We can call a singleton as a lazily initialized global class which is useful when you have large objects — memory allocation can be deferred till when it's actually needed.


1 Answers

There are several questions in there:

is this a good approach?

Yes. There is perhaps an argument for placing the ISR in the same module as the access functions and data it shares, treating it as an access function itself allowing it to read the data directly without the access wrapper overhead.


Is it better/worse/equal to simply have a bunch of globals?

Much worse. With a global where are you going to place your access mutex, data validation or breakpoints? It increases module coupling, and that should always be minimised.


Any major drawbacks?

Not really. There is a function call overhead which may be critical in an ISR; but if that were an issue you would not be calling printf() in an ISR! You can mitigate any possible performance penalty applying my earlier suggestion about placing the ISR in the data module, or by in-lining the code - but your compiler is free to ignore that, and may do so if debugging is enabled, and may also inline regardless if optimisation is enabled. Some compilers have a "forced" inline extension that the compiler is not allowed to ignore; but it is not portable.

One significant benefit is that if the variable is non-atomic, you need some access protection mechanism to ensure consistent access - and that is most easily and safely performed by having access functions. In this case you might have get / set functions that disable and re-enable the interrupt around the access for example, or use a spin-lock (suitable for where the ISR writes and the normal context reads - not the other way around as you have here - don't lock the ISR indefinitely!) .


I also thought I could use some sort of mix like still having the global variables to allow direct manipulation by the ISR (since function calls from the ISR are sometimes frown upon) and the functions in every other case. Would this be better?

Not really - see my point above about function call overhead and placement of the ISR with the data. The problem with calling functions in an ISR is seldom a time-overhead issue, but rather that the implementer of the function may not have designed it to be called safely and efficiently from an ISR and it may use excessive stack, non-deterministic execution time, busy-wait or not be re-entrant or thread-safe. Calling third-party or standard library functions for example may be ill-advised; calling functions you have specifically written and designed for the purpose and conforming to your specific constraints is not necessarily a problem.


All you need to know about why globals are a bad idea and appropriate ways to avoid them can be found in Jack Ganssle's article "A Pox on Globals" - it is also an entertaining read.

like image 166
Clifford Avatar answered Nov 14 '22 23:11

Clifford