4

A couple years ago I learned that global variables are bad and should be avoided. But I know they are sometimes unavoidable, at least in an embedded system. What do you think is the most elegant way to work with them?

In my projects I have a file called globals.h where I define all my global variables:

#ifndef GLOBALS_H
#define GLOBALS_H
extern int16_t    gVariable1;
extern int16_t    gVariable2;
….
#endif

In my main project file I declare all global variables:

/*
***********************************************************************
*                            global variables                         *
***********************************************************************
*/
    int16_t     gVariable1 = 0;
    int16_t     gVariable2 = 0;


int16_t main (void)
{
    gVariable1 = 6;

    //  do other stuff
}

And know I include globals.h in every other file of the project which needs access to a global variable.

That works fine, but is there a more elegant way to handle that?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Mike
  • 4,041
  • 6
  • 20
  • 37
  • 1
    That's about right, unless you decide to divide the global variables up so that one set is declared in `header1.h` and defined in `source1.c`, while the second is declared in `header2.h` and defined in `source2.c` (or divided into more than two sets of files). You might find some ideas in [How do I use `extern` to share variables between source files?](https://stackoverflow.com/questions/1433204) but frankly you've got the core ideas already — declare the variables in headers, and define them in specific source files, and use the headers everywhere that needs access to any of the variables. – Jonathan Leffler Oct 26 '18 at 12:02
  • 2
    Note that elegance should not be a final goal. Typical goals are to make programs perform certain functions or to improve performance. Elegance is a tool. Elegance often aligns with good design, and it also helps make it easier for humans to understand, remember, and work with software (and to enjoy the work). So seeking elegant management of global variables is good when it is serving useful purposes. But elegance is only a tool; we should not insist upon it when some conflicting need arises. – Eric Postpischil Oct 26 '18 at 13:30

2 Answers2

3

I am not sure that global variables are bad in all cases, but you really need to work hard to have very few of them (otherwise, your code in unreadable). For example <stdio.h> has stdout, and it won't be better if it was replaced by some FILE*get_standard_output(void); getter function.

As a rule of thumb, avoid having more than 4 or 5 global variables in your entire program (recall the magical number seven as a hint on our cognitive limitations).

However, you could pack (cleverly and with good taste, to keep your code readable) several related global variables into a single one of struct type. With your example, that could mean in your globals.h:

struct globalstate_st { int16_t v1, v2; };

then

extern struct globalstate_st gs;

and you would use gs.v1 instead of gVariable1; if you compile with optimizations, the performance of using gs.v1 is equivalent to using gVariable1.

BTW, if you have a multi-threaded program, you generally should protect global data with some mutex (or some other kind of synchronization or atomicity). Consider reading this pthread tutorial.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
2

Global variables are not dangerous. It help. But best practice, always keep the scope of the variable limited.

Set the global variable with static and expose function to get and set value.

Eg: in global.c

static int gMyGlobalVariable;

int getMyGlobalVariableValue()
{
   return gMyGlobalVariable;
}

void setMyGlobalVariableValue(int set)
{
   gMyGlobalVariable = set;
}

Eg: in global.h

void setMyGlobalVariableValue(int set);
int getMyGlobalVariableValue();

This will give better control on a multi threaded situation.

  • 1
    This isn't really a "global" variable, as it isn't available globally throughout the project. Formally, it is a _file scope_ variable with internal linkage. This is perfectly fine, particularly in single core embedded systems. Unlike `extern`, which makes the variable "global". – Lundin Oct 26 '18 at 12:56
  • 1
    Global variables are dangerous because they increase the opportunity for error. In ideal programming, they are used properly and have no effect on performance or behavior. However, humans are not ideal. They make mistakes, and opportunities to make mistakes should be minimized. – Eric Postpischil Oct 26 '18 at 13:28
  • This changes every access to a global variable to a function call (which cannot be inlined across units by most toolchains), adding to space and time. The question mentions embedded systems, where space and time may be precious. Using access functions limits the scope partially, by forcing access to be in the form of a function call, so a simple identifier cannot be confused as one for a local identifier when it is for a global variable. But it does not truly limit scope, as access remains available everywhere. The same effect could be achieved simply by naming the variables distinctively. – Eric Postpischil Oct 26 '18 at 14:07
  • Note that the above comment neglects multithread, which is mentioned in the final sentence of the answer but not reflected in the code shown. If multithreading issues are involved, the question changes. – Eric Postpischil Oct 26 '18 at 14:09