Search

4.2 — Global variables and linkage

In the last lesson, you learned that variables declared inside a block are called local variables. Local variables have block scope (they are only visible within the block they are declared), and have automatic duration (they are created at the point of definition and destroyed when the block is exited).

Variables declared outside of a block are called global variables. Global variables have static duration, which means they are created when the program starts and are destroyed when it ends. Global variables have file scope (also informally called “global scope” or “global namespace scope”), which means they are visible until the end of the file in which they are declared.

Defining global variables

By convention, global variables are declared at the top of a file, below the includes, but above any code. Here’s an example of a couple of global variables being defined.

Similar to how variables in an inner block with the same name as a variable in an outer block hides the variable in the outer block, local variables with the same name as a global variable hide the global variable inside the block that the local variable is declared in. However, the global scope operator (::) can be used to tell the compiler you mean the global version instead of the local version.

This code prints:

global value: 4
local value: 8

However, having local variables with the same name as global variables is usually a recipe for trouble, and should be avoided whenever possible. By convention, many developers prefix global variable names with “g_” to indicate that they are global. This both helps identify global variables as well as avoids naming conflicts with local variables.

Internal and external linkage via the static and extern keywords

In addition to scope and duration, variables have a third property: linkage. A variable’s linkage determines whether multiple instances of an identifier refer to the same variable or not.

A variable with no linkage can only be referred to from the limited scope it exists in. Normal local variables are an example of variables with no linkage. Two local variables with the same name but defined in different functions have no linkage -- each will be considered an independent variable.

A variable with internal linkage is called an internal variable (or static variable). Variables with internal linkage can be used anywhere within the file they are defined in, but can not be referenced outside the file they exist in.

A variable with external linkage is called an external variable. Variables with external linkage can be used both in the file they are defined in, as well as in other files.

If we want to make a global variable internal (able to be used only within a single file), we can use the static keyword to do so:

Similarly, if we want to make a global variable external (able to be used anywhere in our program), we can use the extern keyword to do so:

By default, non-const variables declared outside of a block are assumed to be external. However, const variables declared outside of a block are assumed to be internal.

Variable forward declarations via the extern keyword

In the section on programs with multiple files, you learned that in order to use a function declared in another file, you have to use a function forward declaration.

Similarly, in order to use an external global variable that has been declared in another file, you must use a variable forward declaration. For variables, creating a forward declaration is done via the extern keyword (with no initialization value).

Note that this means the “extern” keyword has different meanings in different contexts. In some contexts, extern means “give this variable external linkage”. In other contexts, extern means “this is a forward declaration for an external variable that is defined somewhere else”. We’ll summarize these usages in lesson 4.3a -- Scope, duration, and linkage summary.

Here is an example of using a variable forward declaration:

global.cpp:

main.cpp:

If the forward declaration is declared outside of a block, it applies for the whole file. If the forward declaration is declared inside a block, it applies within that block only.

If a variable is declared as static, trying to use a forward declaration to access it will not work:

constants.cpp:

main.cpp:

Note that if you want to define an uninitialized non-const global variable, do not use the extern keyword, otherwise C++ will think you’re trying to make a forward declaration for the variable.

Function linkage

Functions have the same linkage property that variables do. Functions always default to external linkage, but can be set to internal linkage via the static keyword:

Function forward declarations don’t need the extern keyword. The compiler is able to tell whether you’re defining a function or a function prototype by whether you supply a function body or not.

File scope vs. global scope

The terms “file scope” and “global scope” tend to cause confusion, and this is partly due to the way they are informally used. Technically, in C++, all global variables in C++ have “file scope”. However, informally, the term “file scope” is more often applied to file scope variables with internal linkage only, and “global scope” to file scope variables with external linkage.

Consider the following program:

global.cpp:

main.cpp:

g_x has file scope within global.cpp -- it can not be directly seen outside of global.cpp. Note that even though it’s used in main.cpp, main.cpp isn’t seeing g_x, it’s seeing the forward declaration of g_x (which also has file scope). The linker is responsible for linking up the definition of g_x in global.cpp with the use of g_x in main.cpp.

Global symbolic constants

In section 2.9 -- Symbolic constants and the const keyword, we introduced the concept of symbolic constants, and defined them like this:

constants.h:

While this is simple (and fine for smaller programs), every time constants.h gets #included into a different code file, each of these variables is copied into the including code file. Therefore, if constants.h gets included into 20 different code files, each of these variables is duplicated 20 times. Header guards won’t stop this from happening, as they only prevent a header from being included more than once into a single including file, not from being included one time into multiple different code files. This duplication of variables isn’t really that much of a problem (since constants aren’t likely to be huge), but changing a single constant value would require recompiling every file that includes the constants header, which can head to lengthy rebuild times for larger projects.

We can avoid this problem by turning these constants into const global variables, and changing the header file to hold only the variable forward declarations:

constants.cpp:

constants.h:

Use in the code file stays the same:

Because global symbolic constants should be namespaced and are read-only, the use of the g_ prefix is not necessary.

Now the symbolic constants will get instantiated only once (in constants.cpp), instead of once every time constants.h is #included, and the other uses will simply refer to the version in constants.cpp. Any changes made to constants.cpp will require recompiling only constants.cpp.

However, there are a couple of downsides to doing this. First, these constants are now considered compile-time constants only within the file they are actually defined in (constants.cpp), not anywhere else they are used. This means that outside of constants.cpp, they can’t be used anywhere that requires a compile-time constant (such as for the length of a fixed array, something we talk about in chapter 6). Second, the compiler may not be able to optimize these as much.

Given the above downsides, we recommend defining your constants in the header file. If you find that for some reason those constants are causing trouble, you can move them into a .cpp file as per the above as needed.

A word of caution about (non-const) global variables

New programmers are often tempted to use lots of global variables, because they are easy to work with, especially when many functions are involved. However, use of non-const global variables should generally be avoided altogether! We’ll discuss why in the next section.

Summary

Global variables have global scope, and can be used anywhere in the program. Like functions, you must use a forward declaration (via keyword extern) to use a global variable defined in another file.

By default, non-const global variables have external linkage. You can use the static keyword to explicitly make them internal if desired.
By default, const global variables have internal linkage. You can use the extern keyword to explicitly make them external if desired.

Use a g_ prefix to help identify your non-const global variables.

Here’s a summary chart of the use of the extern and static keywords for non-const and const variable use cases:

Quiz
1) What’s the difference between a variable’s scope, duration, and linkage? What kind of scope, duration, and linkage do global variables have?

Quiz Solutions

1) Show Solution

4.2a -- Why global variables are evil
Index
4.1a -- Local variables, scope, and duration

157 comments to 4.2 — Global variables and linkage

  • Jim

    This is the most confusing section so far! ;+P Final (I hope) confusion concerns "static". In your ‘chart’, you say:
    "// Initialized definition:

    const int g_y(1);  // defines initialized static variable (internal linkage)"
    Why is this constant variable (confusing enough!) labeled as "static"?

    Never mind. I didn’t read the rest of the comments and you answered my question with “Global const variable are static by default”. I just missed that in the text… several times. :wallbash:

    Thanks for your great teaching gift to us!

    • Alex

      Yes, it’s super confusing. The good news is that you won’t be declaring global variables very often (and if you do, they’ll most likely be const values in a header somewhere).

  • Michael

    Hi Alex,
    I made a test and defined a global variable below a function definition instead of putting it at the top of the file:

    The compiler says that g_test is an undeclared identifier.

    Does this mean that global variable’s scope is not exactly all of the file? Rather, it starts from the point of definition till the end of the file?

    Is that also why you should put its definition at the very top of the file?

    Thank you!

    • Alex

      Yes, even though the variable is global in nature, the parts of the file above where the variable is defined can’t see the variable (unless you’ve forward declared it).

  • jack

    Hi Alex, excellent tutorials you made.
    so what should be put in constants.cpp , forward declarations or the actual constants and what should we do in case we need a compile-time constant.

    • Alex

      constants.cpp should contain the actual constant definitions.

      If you need a compile time constant, put the constant definition in the header file. I recommend using the header method (at least to start) anyway.

  • Cat

    Two questions: what exactly is covered by the namespace? i’m trying to parse together what the usages of namespace ought to be.
    and i have a confusion i can’t quite resolve. when you say "However, there is a downside to doing this: these constants are no longer considered compile-time constants, and thus can’t be used anywhere that requires a compile-time constant."
    So what exactly would be a formidable example of compile-time constants? and how exactly does that relate to the example/method shown of symbolic constants and headers? and also how does that differ from non-compile time constants? not quite connecting the dots there and any compare and contrast will help very greatly.
    Just wanna say thank you as well! I was terribly skeptical about an all text/reading tutorial, but jeez this is way better than most video tutorials! Thank you for your service! srsly.

    • Alex

      I’m not sure I understand your first question. Anything can be put inside a namespace. Namespaces are just containers to help prevent naming collisions.

      A formidable example of a compile-time constant would be as the length of a fixed array (which we cover in chapter 6):

      Non-compile time constants would be like a const function parameter. It’s treated as const within the function, but the value isn’t known until runtime:

      • Cat

        Thank you kindly! I think I am starting to understand the difference between compile time vs runtime.
        In the example under symbolic constants section with the adjusted header method, why exactly would these values not be resolved at compile-time? I can see the clear difference in how the values are handled between declaring the const values directly in the header, vs. simply calling the values directly in .cpp files instead. But why does this difference mean that the const values are resolved at runtime?
        Hopefully i’ve worded this well enough. :p

        • Alex

          I realized I made a minor mistake: the const values in the .cpp file ARE considered compile time constants within the file in which they are defined (constants.cpp). This is because the compiler can see the actual definition for those constants.

          However, everywhere else, the compiler only sees the forward declaration, and it’s up to the linker to connect the identifier with the actual definition in another file. That happens post-compile, so the compiler can’t treat it as a compile time constant.

          • Cat

            AH okay that makes MUCH more sense. so the trade off for that method would just be that you would have to keep track of the values you are running through those variables i suppose?

            • Alex

              > so the trade off for that method would just be that you would have to keep track of the values you are running through those variables i suppose?

              I wouldn’t consider that a trade-off. Half the point of using symbolic constants is so you don’t have to remember specific values, just the name of the thing you want.

  • umang

    what is the duration of global variables having external linkage?

  • AMG

    Alex,
    "Variables declares outside of a block are called global variables". There are many blocks, so outside of which block? Should we say a variable, which is accessible in any block of a file, is global.
    Accessible, visible or to be used - means the same - accessible?
    About linkage … Basically linkage either extends (extern) or constrain (static) the scope.
    1. The most intuitive understanding of global scope is the example of defining constants via namespace Constants in .cpp and .h files. No forward declaration or any additional words are required, except ‘Constants::’.  
    2. Extern - is a master key to unlock access to a variable, declared in other file.
    3. Static - is master key to block access to a variable from other files.
    4. The most intuitive understanding local variable is block variable, declared and defined inside of { }.

    • Alex

      A global variable is a variable that is declared outside of _all_ blocks. A variable declared in any block is a local variable. Both global and local variables follow normal scoping rules, where they can be seen by everything after the point of declaration, to the point where they go out of scope (which for local variables is the end of the block in which they are declared, and for global variables is the end of the file).

      I have a summary of all of this stuff in a couple of lessons.

  • Curiosity

    these constants are no longer considered compile-time constants, and thus can’t be used anywhere that requires a compile-time constant.

    Why did u say this when forward declaration of constants was done in header files instead of their initialization………??
    U said that in this :-
    constants.cpp

    constants.h:

    Use in the code file stays the same:

    • Alex

      When the top case is included in other files, the compiler can see the initialization values, so it can treat those as compile time constants. In the bottom case, only the forward declarations are included, and the linker must link those declarations up to the actual variables. Since the linker happens after the compiler, the compiler doesn’t have access to the initialization values (except in the specific .cpp file where they are defined) and thus they generally can’t be used as compile time constants.

  • Ahtazaz Khan

    Hi great Teacher(Alex)!
    I have a question about static keyword, What means it? where to used it and does its value change time to time or will remain same in the whole program…? please  explain static keyword…? what here it means ‘static int 6;’ ,ok here it’s int value of 6 but what the purpose of here static…?? i have a lot of confusion regarding this…
    Thanks in advance.

  • Dennis

    Further clarification of static globals: ‘file scope’ scope of the whole ‘translation unit’ and a translation unit includes all other files added with #include directive, not just the one single file where the static global is written in.

  • Max

    Hello. First, I want to thank you for your C++ tutorial, I really think it is the best textbook for C++, most comprehensible and concise. And I understand, that it is hard to find a balance between this two. So, I want to write about my own experience with this article, and try to figure out why it was so hard for me (and may be some other people from comments section) to understand it. May be it helps to make some fixes, that is not so obvious.

    I’ve read the article and comments several times, but still was deeply confused about "extern" keyword. After a couple hours of reading and thinking, I suppose I understood it, but I’m not 100% sure. So, correct me if I’m wrong.

    So, extern keyword has 2 meanings:
    1) to make a variable external (visible in other files)
    1a) but it’s already external by default for normal (non-const) variables, so you don’t have to use this keyword in that case
    1b) and you CANNOT use this keyword for undefined variables, because compiler/linker will think you’re using the second meaning of extern keyword.
    2) forward declaration for variable, that was declared in some other file
    2a) and you HAVE TO use this keyword in order to access variable from another file
    2b) it doesn’t matter if it’s const or not

    Now, after (I hope) I understood this, I re-reading this article and I suprisingly see, that aricle was absolutely correct, and everything I had so much trouble with, was already there. So, I’ll try to de-cypher why I had hard times understanding it. Some of this points may be obvous for everybody, but me, but I’ll try to write as much details as possible.

    1) In section "Internal and external linkage via the static and extern keywords" we learn, that to make variable external (visible in other files) we should declare it with keyword extern (and it’s default for non-const). But at this point of reading, we have no clue, that it is _necessary_ to use keyword "extern" second time - in other file, in which we want to use it. Yes, now I see the sentence about that in next section, but I can swear I didn’t see it while I was re-reading this article several times. I think the reason is - after I read this section ("Internal and external linkage…"), I somehow assumed, that this is enough to make a variable visible in other files, so when I read next section ("Variable forward declarations via the extern keyword") I assumed it describes some other completely separate case (for example, if we didn’t declared variable with extern keyword in other file). I think this is the main reason of my misunderstanding, and while article is textually correct, I think absence of some linkage (no pun intended) between this sections make it really hard to grasp.

    2) "Similarly, in order to use an external global variable that has been declared in another file, you have to use a variable forward declaration. For variables, creating a forward declaration is also done via the extern keyword (with no initialization value)." - here it is, sentence I didn’t see that "you HAVE TO use a variable forward declaration". And I had some trouble with the word "also" from second sentence. For some reason (I think because it is too far away from its context) I thought "also" means "it can be done with or without extern keyword". Now I understand it means "as in previous case, from previous section", but I got it only after already started to write my first version of this long comment, describing my troubles in understanding different sentences. Only after that "clicked" in my head - I completely understood the whole thing.

    3) "Note that if you want to define an uninitialized non-const global variable, do not use the extern keyword, otherwise C++ will think you’re trying to make a forward declaration for the variable." - that is not so important, but still. Yes, it was probably my fault, that I didn’t see an emphasis on the word "uninitialized". I only understood this sentence after I read an answer about this in comments. But now you can imagine how confusing it was for me when I read it the first time, after all confustions I already got before that =)

    So, I think that’s the main points. I hope it can help improving this article for the next readers. Thank you for your time, spent in reading my too-long comment and thank you again for your job making this great tutorial available for people around the world =)

  • Nguyen

    Hi Alex,
    .
    .
    .
    Similarly, if we want to make a global variable external (able to be used anywhere in our program), we can use the extern keyword to do so:

    extern double g_y(9.8); // g_y is external, and can be used by other files

    int main()
    {
        return 0;
    }
    .
    .
    .
    .
    Here is an example of using a variable forward declaration:

    global.cpp:
    // define two global variables
    int g_x;
    int g_y(2);
    // in this file, g_x and g_y can be used anywhere beyond this point

    main.cpp:
    extern int g_x; // forward declaration for g_x -- g_x can be used beyond this point in this file

    int main()
    {
        extern int g_y; // forward declaration for g_y -- g_y can be used beyond this point in main()

        g_x = 5;
        std::cout << g_y; // should print 2

        return 0;
    }

    I am wondering why you did not use extern keyword in global.cpp?

    Thanks, Have a great day.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter