Search

4.2 — Global variables and linkage

In the last lesson, you learned that variables declared inside a function 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 function 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 function are assumed to be external. However, const variables declared outside of a function 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 variable forward declaration is declared outside of a function, it applies for the whole file. If the variable forward declaration is declared inside a function, 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.

The one-definition rule and non-external linkage

In lesson 1.7 -- Forward declarations and definitions, we noted that the one-definition rule says that an object or function can’t have more than one definition, either within a file or a program.

However, it’s worth noting that non-extern objects and functions in different files are considered to be different entities, even if their names and types are identical. This makes sense, since they can’t be seen outside of their respective files anyway.

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 (to avoid naming conflicts with other identifiers in the global namespace) 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

188 comments to 4.2 — Global variables and linkage

  • Chris

    Hi Alex,

    at second paragraph you said "Global variables have global scope (also called “global namespace scope” or “file scope”)". it is true global scope also called file scope? i google them, and i found (at many question in stackoverflow) they are different. file scope is just in a file which mean variable/function have that scope cannot used at other file. global scope is in entire program which mean variable/function have that scope can used at other file.

    so the different between internal global variable and external global variable is only the linkage? internal doesn't have linkage, but external does?

    thank you

    • Alex

      In C++, file scope and global scope are the same thing. However, informally, sometimes people use the terms as you suggest (making the definitions a combination of file scope and linkage). I've added a section to this lesson called "File scope vs. global scope" where I try to disambiguate this question further.

  • Milos

    Hi Alex,

    thnaks for tutorial!

    In the first example you should write void doSomething(), or write return statement.

  • Matt

    At the top of the lesson, you wrote:
    "local variables... have automatic duration (they are created when the block is entered and destroyed when the block is exited)."

    According to the previous lesson, local variables are created at the point of definition within a block, not necessarily when the block is entered.

  • Am

    Hi Alex,

    line 11 in summery code should be const keyword or static?

    "const int g_y(1); // defines initialized static variable (internal linkage)"

    Thanks

  • Pedro Peck

    How do I extern a multidimensial array?

  • Jonas

    Hi Alex!

    First of all, thanks for this very concise tutorial - it has really helped me improving my programming skills.

    But now to my question, which might not be as relevant since we're only working with IDEs but I'm still curious:
    How do you compile programs with global variables in separate files (like in your example with global symbolic constants) with a makefile?

    I have been able to successfully compile programs with a makefile when doing this with functions in separate files, but it wouldn't compile with extern const variables.
    Thanks

  • Andy

    ugh, been re-reading some of this for the last ~hour, and still can't figure out why this doesn't make sense to me. You have the note "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.", but are you not doing exactly that in your earlier example?

    • Alex

      My example is of an initialized non-const variable. The warning was for uninitialized non-const variables.

      Because this area tends to cause so much confusion, I've provided a summary table in lesson 4.3a.

  • Tung Nguyen

    Hi there,

    Thank you for the great website. It helps me a lot with C++. As I read through the section, a question arises.

    Is there any difference between global variable and global variable with the keyword extern before it?

    As I know, global variables have external linkage which it can be used in many files. Why do we need the keyword extern before it?

    Thank you for your time.

    Best,

    Tung Nguyen.

    • Alex

      You don't need to use the extern keyword for non-const global variables, as they're already extern by default. But const global variables are internal by default, so if you want to use them across multiple files you'll need to explicitly use the extern keyword:

  • Professzore

    Hi,

    In this very short line of code:

    unary operator :: has the highest precedence among all operators, so will be evaluated first (we'll use the global value variable), and then decrease it's value by 1 (post-decrement operator), and finally assign it to the global value variable.
    Do I understand it well or not?
    Thanks

    • Alex

      Yes, :: is evaluated first. Then operator-- is evaluated, which decrements value by 1, and evaluates to the former value of value, which is discarded.

      There's no separate assignment step here.

  • Chris

    I have copped your code that uses a header file to declare certain constants and use them in a different file, but the IDE I use fails to build an executable, even after changing "radius" to a literal integer.

    I have had other strange problems with Eclipse's C++ IDE.  Do you know if there are particular problems with this specific IDE?

    Here is the code:

    main4_3.cpp

    helpper.h

    helpper_4_1.cpp

  • J3ANP3T3R

    i got a bit confused. in this section ;

    "While this is simple (and fine for smaller programs), every time constants.h gets #included, each of these variables is copied into the including code file"

    i thought the Header Guards would have prevented that from happening ?

    #ifndef CONSTANTS_H
    #define CONSTANTS_H
    #endif

    • Alex

      I've updated the lesson text slightly to address this: 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.

  • Yuval

    Thank you so much Alex for running this great site for so long - I really LOVE it that it is so well updated and explains every little question I might ask myself - I haven't encountered this excellent level of detail anywhere else. The comments section is also very helping, as it answers those very intricate topics that are sometimes still bugging me even after your wonderful lessons 🙂
    I really suggest adding the comments about header-guards not actually guarding from defining the same variables in different files instead of just declaring them, in the lesson's body itself. Thanks!!!

  • OPENG

    While this is simple (and fine for smaller programs), every time constants.h gets #included, each of these variables is copied into the including code file. If constants.h gets included 20 times, each of these variables is duplicated 20 times. That’s not too much of a problem here, but if this list of constants were large, and/or included memory-intensive variables, it could lead to code bloat.

    Doesn't Header Guards work here? Why included 20 times? Doesn't preprocessor work?

    • Alex

      Header guards prevent a header file from being included multiple times in a single file.
      Header guards do not prevent a header file from being included once into multiple different files.

      Therefore, if your header file is included once into 20 different files, you'll end up with 20 different copies of the contents, header guards or not.

  • MechanicNeurons

    NOTE FOR ALEX: contents are quite precious but the website format a little bit tricky. when I want to work half screen the main content shrinks in the middle of the webpage in order to show left and right columns without horizontal scroll. after it shrinks it is very difficult to read especially the example codes in the text. that's why I use adblock. I blocked the left and right columns and now I only see the middle column as wide as chrome window. (if you are bored go to the last sentence). adblock remembers this configuration even after I pass to the next chapter. but adblock also blocks the ads (you don't say). generally I dont use adblock on the websites as long as I believe they do a good job and also if they don't have very very annoying adds. but unfortunately your website has written a new rule to force me to use. everyday I visit this website and study, when I am tired I go to internet explorer and click your adds.
    please rearrange your website so when we use it half screen it will show the main content as wide as possible, so I (maybe we) can disable adblock..

    • Alex

      Okay, I'm running an experiment. When your window is half of your screen or smaller, the right sidebar should collapse. The left one will stay since it contains navigation elements.

  • Pan

    Hey Alex,
    I tried to include the "constants" header file into multiple cpp files:

    But there were no performance issues as you said that these constants will be copied multiple times, the visual studio compiler gave me error messages.(something like that variables have been defined multiple times.)

    Did I make some mistakes?

  • Jim

    Alex,
    This lesson is a bit confusing.  Are you saying the keywords static and extern are used to refer to a functions linkage? That you can't use static int add (int x, int y);, or use a (static const )to do a forward declaration of a function but int add ( int x, int y ); will work?  
    In the note that follows, it looks like you actually did what the note says not to do in the second main.cpp function above this  when you used  extern int g_x;
    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.  I may be missing something here, can you please help.

    • Alex

      Yes, the lesson is difficult because C++ is confusing in this regard. Static and extern are used to explicitly set the linkage of a function or variable to internal or external respectively.

      You can use static int add(int x, int y) to do a forward declaration, but only if the function add() is declared in the same file (because static functions have internal linkage).

      > 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.

      int g_x; tells the compiler that I'm defining an int variable named g_x, and that variable should be instantiated.
      extern int g_x; tells the compiler that I've defined a int variable named g_x in another file, but want to use it here.

      So if we want an uninitialized non-const global variable, we don't use extern, otherwise we fall into the second case.

  • Muhammad Kamal

    "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." <--- Assumed by the compiler or generally between developers and programmers?

    Proofreading ^__^

    • A variable with internal linkage is called [b]a[/b] internal variable
    • Note that if you want to define [b]a[/b] uninitialized non-const global variable
    • and the other uses will simply [b]reference[/b] (should be 'refer to') the version in constants.cpp.

    Also do I get notified somehow that someone replied to my submission? Or I'll have to keep checking back?

  • Lokesh

    @Chang
    Because the name(identifier) of a namespace should be unique. "Constants" and "constants" are two different identifiers. So, when the compiler sees the forward declaration of 'pi' it compiles fine. But in the linking stage, when the linker looks for a definition of 'pi' in "constants" namespace, it cannot find it because there is no namespace named "constants".

  • Chang

    Hi Alex, I manually typed out the codes for constants.h and constants.cpp in the following way:

    constants.cpp

    constants.h

    it has an error, but i resolved in when i changed the capital "C" in constants.cpp to a small letter "c". Seems like the namespace definitions in both the .cpp and .h files need to be the same. Why is this so?

  • Lokesh

    "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 reference the version in constants.cpp."
    How is a global variable referenced? Is this handled by the linker? If so, is it the same way as a function linking works?

    • Alex

      A global variable is referenced by name, just like any other variable. The linker handles figuring out how to connect references to the global variable with where the global variable was defined. Function linking works the same way (you call a function that lives somewhere, it's up to the linker to connect the function call to the function definition, which may be in a different file).

  • Soul

    Hi, I tried following your instructions here but got some issues. What I have is:

    main.cpp

    Console.h

    functions.cpp

    While the extern keyword is in namespace, I get the error:
    "
    -------------- Build: Debug in 6th Project (compiler: GNU GCC Compiler)---------------

    mingw32-g++.exe -Wall -fexceptions -g -std=c++11  -c "C:\Users\Cybermastah\Documents\CB projects\6th Project\functions.cpp" -o obj\Debug\functions.o
    mingw32-g++.exe -Wall -fexceptions -g -std=c++11  -c "C:\Users\Cybermastah\Documents\CB projects\6th Project\main.cpp" -o obj\Debug\main.o
    mingw32-g++.exe  -o "bin\Debug\6th Project.exe" obj\Debug\functions.o obj\Debug\main.o  
    obj\Debug\main.o:main.cpp:(.rdata+0x8): multiple definition of `Consta::gravity'
    obj\Debug\functions.o:functions.cpp:(.rdata+0x8): first defined here
    collect2.exe: error: ld returned 1 exit status
    Process terminated with status 1 (0 minute(s), 1 second(s))
    0 error(s), 0 warning(s) (0 minute(s), 1 second(s))

    "

    But when I REMOVE the extern keyword it works fine. I tried adding 'using namespace Consta;' to both files and to one file and the problem persisted regardless. I can't get the extern keyword to work properly.

    • Soul

      Never mind, just realized I need to treat the header file as merely the place to stick forward declarations reaching into a cpp file for the number instead. I thought "since it works WITHOUT extern, why would I use extern?" So I went back to the lesson to see why extern is useful and remembered that you mentioned to use the header as a place to stick the namespace as a forward declaration instead, leading to a cpp file where the actual value is located.

      I'd still be grateful for an explanation for why my previous code refuses to compile though 🙂

      Even if it makes further repeats of this and bloats the code, I don't see why it wouldn't do so anyway (unless code::blocks specifically doesn't allow it?).

      • Alex

        An initialized constant declared with the extern keyword has external linkage. Since your gravity variable is getting #included in both main.cpp and functions.cpp, both get a copy of the definition for gravity. Since both versions of gravity have external linkage, they collide, and this causes a naming conflict.

        Removing the extern causes them to have internal linkage. main.cpp and functions.cpp still get a copy of gravity, but with internal linkage neither copy of gravity can see the other, so there's no conflict.

  • Ella

    I'm confused about non-const variables and the need for extern.

    It says "By default, non-const variables declared outside of a block are assumed to be external."

    Then later on it says "Non-const variables are a little more complex since they can be defined either initialized and uninitialized, which is why the explicit use of extern is required."

    Why is extern required if non-const variables are extern by default?

    • Alex

      With functions, a function without a body is assumed to be a forward declaration for a function declared elsewhere.
      With non-const variables, C++ assumes an uninitialized non-const variable is meant to be an uninitialized variable declaration. If you want it to be a forward declaration for the variable, you have to use the extern keyword.

      This sentence seems to cause more confusion than clarity, so I've removed it. 🙂

  • Peter

    While I didn't try to compile the code myself, I still think there is a mistake in the code:

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

    Then the code:
    constants.cpp:

    constants.h:

    There shouldn't be the "extern" modifier in "constants.cpp", because those variables need to be defined somewhere (that is with no "extern" modifier). Am I right ?
    Also, if you define variables inside of a namespace ("Constants" in the example), can you still say that those variables are global ?

    • Peter

      Sorry for that last question - should have read the chapter about namespaces, before posting any questions - I got it now.
      Nonetheless, the gist of my previous comment remain - there shouldn't be any "extern" keywords in "constants.cpp"

    • Alex

      Remember that const variables have internal linkage by default. The extern in the constants.cpp makes these variables have external linkage.

      This is one of the more confusing parts of C++, in that the extern keyword has two meanings depending on context. It can mean, "I'm declaring a variable here and I want it to have external linkage", or "I've declared a variable elsewhere and want to use it here".

      That's why I provided the chart in the summary. You can see that these variables match this pattern:

      extern const int g_w(1); // defines initialized const global variable (external linkage)

      A global variable in a namespace is still a global variable, it's just inside a namespace as well. 🙂

  • Sean Kelly

    Hey Alex,

    I was working on a small project of mine when I decided that for the sake of learning I wanted to split my constant variables from one header to another, justly naming the new header, constants.h. I also decided that I wanted to initialize the constants in another .cpp file named constants.cpp and have it #include the prior header file.

    Now when I decided to call the constant variable in my main .cpp file using cout or the like it works fine, HOWEVER, when I decided to use my variable in the creation of a multi-dimensional array it gives me the following error, "Error: expression must have a constant value", funny thing is I am declaring these variables as extern and const and I am including the header file in both my main.cpp and constants.cpp, so I am at a loss.

    • Alex

      C++ is full of little weirdnesses, and it appears you found one.

      When a constant is external, the compiler doesn't know what value it has at compile time (it only knows at link time). Therefore, an extern const can't be used as a compile-time constant (which is required for fixed-size arrays).

      Since your size is presumably an integer, I'd just define the const in the header file directly. If it gets copied into ten or twenty .cpp files, it's no problem, it's just an integer.

  • mrrhq

    Hmm... I never really liked learning about how the code and variable abstraction work this way using static and extern types. It makes C++ more of a confusing language to me. So using extern is like using a "prototype variable", much like prototyping a function, right?

    When you prototype a function, you have to specify the name of the function and its arguments, but you don't prototype a variable, you declare it. So when you use extern, does that mean you declare it in a different scope? Does that mean that a global variable no longer becomes global? I don't understand the point of this...

    I also think "static" has to be the most confusing keyword/statement of them all. I have no real technical information of what it does. Does it just protect the variable from being used by other scopes or outside the function, or does it have more uses? Sorry but, if I ever program in C++, I will never use the static statement, since nobody seems to really give me information on EXACTLY what it does, EXACTLY. It's kinda stupid.

    • mrrhq

      Okay, I'm now trying to read Section 4.3, which talks about the static keyword, but I'm still a little confused about extern. Maybe I'll find a use for it someday.

    • Alex

      Externing a variable is just like prototyping a function (except for variables). A global variable is still global, it's just now also accessible in the scope in which it was externed.

      In the context of a global variable, static causes the variable to have internal linkage, so it can't be extern'd. Static has a different meaning in the context of local variables (it changes their duration). We cover that in lesson 4.3.

  • Samitha

    Thank a lot Alex. Your C++ tutorials taught me C++. This tutorial set is great.

  • Benny

    what are these files you talk about, which headers are included in? aren't files compiled away?

  • omar

    Am glad that i found this site Alex .But am having a bit of a problem right now . It seem like even tho i can understand the topics and the ideas when u give us a quiz to write i always get it wrong and my code is way off to yours . How can i learn to implement your topics into my code and how can i improve . Thank you

    • Alex

      It's okay for your code to be different, as long as you're following good programming principles. My solutions indicate how I'd solve the problem. If you did something differently than me, make sure you understand how my program works, then look at your own program and see how you might have improved it. Then you'll know for next time. It's all about learning along the way, not necessarily doing it perfectly the first time. 🙂

  • sniper

    • Alex

      I ran this in Visual Studio 2015 and got 12 for the second to last value, and 16 for the final value (which is correct, as you've used a post-increment rather than a pre-increment here).

Leave a Comment

Put all code inside code tags: [code]your code here[/code]