When is it ok to use a global variable in C?

CGlobal Variables

C Problem Overview


Apparently there's a lot of variety in opinions out there, ranging from, "Never! Always encapsulate (even if it's with a mere macro!)" to "It's no big deal - use them when it's more convenient than not."

So.

Specific, concrete reasons (preferably with an example)

  • Why global variables are dangerous
  • When global variables should be used in place of alternatives
  • What alternatives exist for those that are tempted to use global variables inappropriately

While this is subjective, I will pick one answer (that to me best represents the love/hate relationship every developer should have with globals) and the community will vote theirs to just below.

I believe it's important for newbies to have this sort of reference, but please don't clutter it up if another answer exists that's substantially similar to yours - add a comment or edit someone else's answer.

-Adam

C Solutions


Solution 1 - C

Variables should always have a smaller scope possible. The argument behind that is that every time you increase the scope, you have more code that potentially modifies the variable, thus more complexity is induced in the solution.

It is thus clear that avoiding using global variables is preferred if the design and implementation naturally allow that. Due to this, I prefer not to use global variables unless they are really needed.

I can not agree with the 'never' statement either. Like any other concept, global variables are something that should be used only when needed. I would rather use global variables than using some artificial constructs (like passing pointers around), which would only mask the real intent.

Some good examples where global variables are used are singleton pattern implementations or register access in embedded systems.

On how to actually detect excessive usages of global variables: inspection, inspection, inspection. Whenever I see a global variable I have to ask myself: Is that REALLY needed at a global scope?

Solution 2 - C

The only way you can make global variables work is to give them names that assure they're unique.

That name usually has a prefix associated some some "module" or collection of functions for which the global variable is particularly focused or meaningful.

This means that the variable "belongs" to those functions -- it's part of them. Indeed, the global can usually be "wrapped" with a little function that goes along with the other functions -- in the same .h file same name prefix.

Bonus.

When you do that, suddenly, it isn't really global any more. It's now part of some module of related functions.

This can always be done. With a little thinking every formerly global variable can be assigned to some collection of functions, allocated to a specific .h file, and isolated with functions that allow you to change the variable without breaking anything.

Rather than say "never use global variables", you can say "assign the global variable's responsibilities to some module where it makes the most sense."

Solution 3 - C

Consider this koan: "if the scope is narrow enough, everything is global".

It is still very possible in this age to need to write a very quick utility program to do a one-time job.

In such cases, the energy required to create safe access to variables is greater than the energy saved by debugging problems in such a small utility.

This is the only case I can think of offhand where global variables are wise, and it is relatively rare. Useful, novel programs so small they can be held completely within the brain's short-term memory are increasingly infrequent, but they still exist.

In fact, I could boldly claim that if the program is not this small, then global variables should be illegal.

  • If the variable will never change, then it is a constant, not a variable.
  • If the variable requires universal access, then two subroutines should exist for getting and setting it, and they should be synchronized.
  • If the program starts small, and might be larger later, then code as if the program is large today, and abolish global variables. Not all programs will grow! (Although of course, that assumes the programmer is willing to throw away code at times.)

Solution 4 - C

Global variables in C are useful to make code more readable if a variable is required by multiple methods (rather than passing the variable into each method). However, they are dangerous because all locations have the ability to modify that variable, making it potentially difficult to track down bugs. If you must use a global variable, always ensure it is only modified directly by one method and have all other callers use that method. This will make it much easier to debug issues relating to changes in that variable.

Solution 5 - C

When you're not worried about thread-safe code: use them wherever it makes sense, in other words wherever it makes sense to express something as a global state.

When your code may be multi-threaded: avoid at all costs. Abstract global variables into work queues or some other thread-safe structure, or if absolutely necessary wrap them in locks, keeping in mind that these are likely bottlenecks in the program.

Solution 6 - C

I came from the "never" camp, until I started working in the defense industry. There are some industry standards that require software to use global variables instead of dynamic (malloc in the C case) memory. I'm having to rethink my approach to dynamic memory allocation for some of the projects that I work on. If you can protect "global" memory with the appropriate semaphores, threads, etc. then this can be an acceptable approach to your memory management.

Solution 7 - C

Code complexity is not the only optimization of concern. For many applications, performance optimization has a far greater priority. But more importantly, use of global variables can drastically REDUCE code complexity in many situations. There are many, perhaps specialized, situations in which global variables are not only an acceptable solution, but preferred. My favorite specialized example is their use to provide communication between the main thread of an application with an audio callback function running in a real-time thread.

It is misleading to suggest that global variables are a liability in multi-threaded applications as ANY variable, regardless of scope, is a potential liability if it is exposed to change on more than one thread.

Use global variables sparingly. Data structures should be used whenever possible to organize and isolate the use of the global namespace.

Variable scope avails programmers very useful protection -- but it can have a cost. I came to write about global variables tonight because I am an experienced Objective-C programmer who often gets frustrated with the barriers object-orientation places on data access. I would argue that anti-global zealotry comes mostly from younger, theory-steeped programmers experienced principally with object-oriented APIs in isolation without a deep, practical experience of system level APIs and their interaction in application development. But I have to admit that I get frustrated when vendors use the namespace sloppily. Several linux distros had "PI" and "TWOPI" predefined globally, for example, which broke much of my personal code.

Solution 8 - C

  • When Not to Use: Global variables are dangerous because the only way to ever know how the global variable changed is to trace the entire source code within the .c file within which they are declared (or, all .c files if it is extern as well). If your code goes buggy, you have to search your entire source file(s) to see which functions change it, and when. It is a nightmare to debug when it goes wrong. We often take for granted the ingenuity behind the concept of local variables gracefully going out of scope - it's easy to trace
  • When to Use: Global variables should be used when its utilization is not excessively masked and where the cost of using local variables is excessively complex to the point where it compromises readability. By this, I mean the necessary of having to add an additional parameter to function arguments and returns and passing pointers around, amongst other things. Three classic examples: When I use the pop and push stack - this is shared between functions. Of-course I could use local variables but then I would have to pass pointers around as an additional parameter. Second classic example can be found in K&R's "The C Programming Language" where they define a getch() and ungetch() functions which share a global character buffer array. Once again, we don't need to make it global, but is the added complexity worth it when its pretty hard to mess up the use of the buffer? Third example is something you'll find in the embedded space amongst Arduino hobbyists. Alot of functions within the main loop function all share the millis() function which is the instantaneous time of when the function is invoked. Because clock speed isn't infinite, the millis() will differ within a single loop. To make it constant, take a snapshot of time prior to every loop and save it in a global variable. The time snapshot will now be the same as when accessed by the many functions.
  • Alternatives: Not much. Stick to local scoping as much as possible, especially in the beginning of the project, rather than vice versa. As the project grow's and if you feel complexity can be lowered using global variables, then do so, but only if it meets the requirements of point two. And remember, using local scope and having more complicated code is the lesser evil compared to irresponsibly using global variables.

Solution 9 - C

You need to consider in what context the global variable will be used as well. In the future will you want this code to duplicate.

For example if you are using a socket within the system to access a resource. In the future will you want to access more than one of these resources, if the answer is yes I would stay away from globals in the first place so a major refactor will not be required.

Solution 10 - C

It's a tool like any other usually overused but I don't think they are evil.

For example I have a program that really acts like an online database. The data is stored in memory but other programs can manipulate it. There are internal routines that act much like stored procedures and triggers in a database.

This program has a hundreds of global variables but if you think about it what is a database but a huge number of global variables.

This program has been in use for about ten years now through many versions and it's never been a problem and I'd do it again in a minute.

I will admit that in this case the global vars are objects that have methods used for changing the object's state. So tracking down who changed the object while debugging isn't a problem since I can always set a break point on the routine that changes the object's state. Or even simpler I just turn on the built in logging that logs the changes.

Solution 11 - C

Global variables should be used when multiple functions need to access the data or write to an object. For example, if you had to pass data or a reference to multiple functions such as a single log file, a connection pool, or a hardware reference that needs to be accessed across the application. This prevents very long function declarations and large allocations of duplicated data.

You should typically not use global variables unless absolutely necessary because global variables are only cleaned up when explicitly told to do so or your program ends. If you are running a multi-threaded application, multiple functions can write to the variable at the same time. If you have a bug, tracking that bug down can be more difficult because you don't know which function is changing the variable. You also run into the problem of naming conflicts unless you use a naming convention that explicitly gives global variables a unique name.

Solution 12 - C

When you declare constants.

Solution 13 - C

I can think of several reasons:

debugging/testing purposes (warning - haven't tested this code):

#include <stdio.h>
#define MAX_INPUT 46
int runs=0;
int fib1(int n){
    ++runs;
    return n>2?fib1(n-1)+fib1(n-2):1;
};
int fib2(int n,int *cache,int *len){
    ++runs;
    if(n<=2){
        if(*len==2)
            return 1;
        *len=2;
        return cache[0]=cache[1]=1;
    }else if(*len>=n)
        return cache[n-1];
    else{
        if(*len!=n-1)
            fib2(n-1,cache,len);
        *len=n;
        return cache[n-1]=cache[n-2]+cache[n-3];
    };
};
int main(){
    int n;
    int cache[MAX_INPUT];
    int len=0;
    scanf("%i",&n);
    if(!n||n>MAX_INPUT)
        return 0;
    printf("fib1(%i)==%i",n,fib1(n));
    printf(", %i run(s)\n",runs);
    runs=0;
    printf("fib2(%i)==%i",n,fib2(n,&cache,&len));
    printf(", %i run(s)\n",runs);
    main();
};

I used scoped variables for fib2, but that's one more scenario where globals might be useful (pure mathematical functions which need to store data to avoid taking forever).

programs used only once (eg for a contest), or when development time needs to be shortened

globals are useful as typed constants, where a function somewhere requires *int instead of int.

I generally avoid globals if I intend to use the program for more than a day.

Solution 14 - C

I believe we have an edge case in our firm, which prevents me from entering the "never use global variables camp".

We need to write an embedded application which works in our box, that pulls medical data from devices in hospital.

That should run infinitely, even when medical device is plugged off, network is gone, or settings of our box changes. Settings are read from a .txt file, which can be changed during runtime with preferably no trouble.

That is why Singleton pattern is no use to me. So we go back from time to time (after 1000 data is read) and read settings like so:

public static SettingForIncubator settings;

public static void main(String[] args) {
    while(true){
        SettingsForIncubator settings = getSettings(args);

        int counter=0;

        while(medicalDeviceIsGivingData && counter < 1000){
            readData(); //using settings

            //a lot of of other functions that use settings.

            counter++;
        }
    } 
}

Solution 15 - C

Global constants are useful - you get more type safety than pre-processor macros and it's still just as easy to change the value if you decide you need to.

Global variables have some uses, for example if the operation of many parts of a program depend on a particular state in the state machine. As long as you limit the number of places that can MODIFY the variable tracking down bugs involving it isn't too bad.

Global variables become dangerous almost as soon as you create more than one thread. In that case you really should limit the scope to (at most) a file global (by declaring it static) variable and getter/setter methods that protect it from multiple access where that could be dangerous.

Solution 16 - C

I'm in the "never" camp here; if you need a global variable, at least use a singleton pattern. That way, you reap the benefits of lazy instantiation, and you don't clutter up the global namespace.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAdam DavisView Question on Stackoverflow
Solution 1 - CDan CristoloveanuView Answer on Stackoverflow
Solution 2 - CS.LottView Answer on Stackoverflow
Solution 3 - CPaul BrinkleyView Answer on Stackoverflow
Solution 4 - CJeff YatesView Answer on Stackoverflow
Solution 5 - CDan LenskiView Answer on Stackoverflow
Solution 6 - CgthuffmanView Answer on Stackoverflow
Solution 7 - CctpenroseView Answer on Stackoverflow
Solution 8 - CDean PView Answer on Stackoverflow
Solution 9 - CJProgrammerView Answer on Stackoverflow
Solution 10 - CKevin GaleView Answer on Stackoverflow
Solution 11 - CSteropesView Answer on Stackoverflow
Solution 12 - Cuser15039View Answer on Stackoverflow
Solution 13 - CyingtedView Answer on Stackoverflow
Solution 14 - COnat KorucuView Answer on Stackoverflow
Solution 15 - CAdam HawesView Answer on Stackoverflow
Solution 16 - CNik ReimanView Answer on Stackoverflow