“The road to programming hell is paved with global variables” - Steve McConnell, Code Complete
“Globals are responsible for all of the evil in the universe, from male pattern baldness to ozone depletion.” - Jack Ganssle, Mars ate my spacecraft!
Global variables are generally not encouraged in programming. Having multiple functions potentially changing the state of a single variable can lead to major problems. According to Phil Koopman in Better Embedded Systems Software, global variables are evil. A global variable is a variable with global scope, so it is directly visible to the entire software system. MISRA Software Guidelines recommend against using global variables (MISRA Report 5, p. 10). IEC 61508-3 recommends a modular approach (p. 79), information hiding/encapsulation (id., p. 93), and a fully defined interface (id., p. 93), which basically recommends against using global variables.
Problems with Global Variables
If your software has global variables in it, every function has access to those variables. In small programs this is an acceptable risk, but as software systems get larger it becomes increasingly difficult to understand which functions actually read and write to these variables. When trying to understand how legacy applications work, you have to take into account every function that writes to the global variable. This makes it hard to understand what each function does because it is hard to know what the global state of the variable will be in each instance.
Global variables can also add to intercomponent coupling. This increases complexity if a large number of components are using global variables. The additional coupling and complexity makes it easier for developers to inadvertently add defects to the software when making updates. Finding and fixing those defects is harder. Coupling with global variables increases the cost (time and effort) needed to make changes to code. All of this affects the impact of change. NASA recommends avoiding “too many intercomponent dependencies. To maximize software reusability, components should not depend on each other in a complex way,” which includes the use of global variables to communicate data between components. (NASA 2004, p. 93)
Raw access to global variables represents an encapsulation violation. The reason to have encapsulation is to increase understanding and make it easier and safer to change source code. This all leads to easier testing, meaning global variables make it harder to unit test.
Embedded applications with limited memory available will often used global variables to handle shared data that is referenced throughout the application. The safest way to use global variables in this context is to assign the responsibility for writing to the global variable to a single component. All other components are only allowed to read from it.
If you are planning on using global variables, here are a couple of issues that will need to be considered:
- When the source code for a global variable is modified, everything that is using the global variable must be recompiled because everything must know its new size and memory footprint.
- If multiple components can write to a global variable, this can lead to inconsistent data in the global variable. If the application is multi-threaded, a locking mechanism will need to be used so that only one thread can modify the variable at a time. If several components are talking to each other through global variables, understanding which component is changing the global variable, and when and how that is happening can be very difficult.
- Global variables can also lead to name collision in which the same variable name is used both by a local variable and a global variable. This hides the global variable. The collision must be resolved for the software to work correctly. There are several ways for correcting or avoiding name collisions including:
- Namespaces – qualifying each name with a different group name, so that the complete names are different from each other
- Renaming – changing the name of either the global variable or the local variable
- Prefixing – putting a unique character(s) before each name so that the names differ
Global variables are generally discouraged in modern programming practices, but they are far too common in legacy code. You might be able to refactor your code to get rid of all global variables, but that depends on the nature of the global variables. If they are small in number, if they mostly read and rarely modified, making wholesale changes may be unnecessary. In that case, relying on documentation, programmer discipline, and code reviews might be enough to ensure they are used properly.
If you are having trouble keeping track of your global variables, Lattix Architect has a global variable report that tracks all read and writes of global variables. Click here for more information and to schedule an evaluation.