Search

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

local value: 8
global value: 4

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. 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 S.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 2.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 lead 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

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

240 comments to S.4.2 — Global variables and linkage

  • mooseymouse

    hi i dont unerstand something how can the compiler differentiate between a forward declaration of an external variable in an other file from defining a local variable like what if i wanted to define an uninitialised external  variable in main you said it wouldn't link as the linker interprets it as a forward declaration for variable in another file.  i am confused by this thanks,

  • Chandler

    All of your examples on this page initialize the variables using parenthesis.

    I thought this was done with the curly braces: { }

    • nascardriver

      Some lessons still use direct- or copy-initialization, thanks for pointing this one out! I updated it to use brace-initialization instead.

  • Tushar

    https://www.youtube.com/watch?v=hDfDnsvEodQ

    This video explains this concept very clearly. Had a hard time understanding this so save yourself and go through this tutorial

  • Fan

    Is it true that the order of initialization of global variables is undefined, even inside a single file? For example, the code

    produces
    1 3
    as if j=0 first, then i is initialized with 0+1=1, and finally j is initialized with 1+2=3.
    But then the code

    produces
    3 2
    as if j is initialized with 2 first, and then i is initialized with 2+1=3.

    • There are several initialization steps for non-local variables. First, variables that are initialized by a constant expression (eg. a number) are initialized. The rest of the variables is zero-initialized. This happens before your program starts running. The values are stored in the binary.
      Then, when your program starts running, the other variables in the current file are initialized in-order (This might also happen before your program starts running, but that's just an optimization).

      Example 1:
      `j` is zero-initialized, because it isn't initialized by a constant expression.
      `i` is zero-initialized, same reason as `j`.
      Now your program starts.
      `i` is initialized (0 + 1)
      `j` is initialized (1 + 2)

      Example 2:
      `j` is initialized to 2, because 2 is a constant expression.
      Now your program starts
      `i` is initialized (2 + 1)

      This order is well-defined.

      To take it a little further

      Output: 1 12 9

      `k` is initialized to 9, because 9 is a constant expression.
      `i` and `j` are 0.
      Now the program starts.
      `i` is initialized (0 + 1)
      `j` is initialized (9 + 3)

      There are exceptions, but none you'd have to worry about just yet.

  • hellmet

    I have a bunch of questions, some stupid perhaps...
    1) Why is it that a const has the exception that it has only internal linkage even when it is declared at the file scope (i.e. outside main)? (The explanation on StackOverflow didn't make sense to me)
    2) How would constexpr change things with each of the declarations shown in the summary? From what I recall (and I hope I understood this well) const is for values that do not change at runtime, once initialized; constexpr need to be initialized by compile time, so the compiler is free to replace all occurrences of the variable with the value it holds. So, does this mean whenever and wherever I include the header with something defined as constexpr, the compiler will replace them with that variable's values?
    3) Clearly, static and extern are opposing concepts. Is there any way I can include my 'secret' variable only select files and not in any other? Say I have a case where I am keeping track of number of students in a file, and to calculate the average expenditure per student, I want to get the number of students. This is a case where the finance.cpp and students.cpp are different, but need access to a single 'secret' variable. From what I've read so far, accomplishing that with static doesn't seem possible.

    • 1)
      It's likely that you need a `const` variable in multiple files. If you need something in multiple files, you put it in a header. A constant never changes, so you initialize it at its declaration. If you initialize a variable with external linkage at its declaration in a header, you'll run into trouble, because it's defined multiple times. If the variable has internal linkage, you can include it multiple times, because the other files don't see it.

      2)

      `g_w` makes me wonder why it's legal, maybe someone else can help.

      `constexpr` tells the compiler that the variable/function can be evaluated at compile-time. What the compiler does with this information is up to it. It might replace the occurrences of the variable with its value, but it doesn't have to.
      `constexpr` variables can be used in combination with `constexpr` functions to make sure that your code _could_ be evaluated at compile-time.

      3)
      `class` and `friend` (Covered later) will help you with keeping your secret. C++20's modules might also help, the future will tell.

      • hellmet

        Okay 3 makes sense!
        But I'm still worried I don't fully understand 1, 2.

        I'm trying to rationalize the meanings of const, constexpr, extern, internal vs external linkage, static and connect the dots so that I better understand and reason with their usage.

        This is how I understood them, please correct me if I'm wrong.

        1) A variable of the form 'int p' declared at the file level has external scope by default. Its forward declared as 'extern int p' in a header file that can be included in files that require it. This assures that any file #include-ing the relevant header file has the same copy.

        2) const, static give a variable internal linkage by default and can be declared+initialized as extern and forward declared in a header file if they are to be used outside the file. Consequently, any files including the header file will get the 'same copy' instead of being assigned new memory each time.  

        3) The advantage (over C) of 'const' having internal linkage is that it allows for both possibilities, having a local copy (by default) or by using the global unique copy allowing for customization of code.

        4) All variables or functions declared as 'constexpr' has a single memory by default, so it's redundant to use extern on its declaration. They can just be used as is, as long they are defined+declared in a header file and included, as they can't be forward declared

        Have I got this right?

        Sidenote, how do I find all my comments? It would be nice to have the links so that I can refer back to them later

        • 1)
          Correct

          2)
          `static` and `extern` can't be mixed. `static` has internal linkage.

          3)
          "global unique" might be misleading. Every file that includes a header in which a `const` variable was declared gets a copy of the variable. All of the variables will have the same value, but they're distinct objects.
          This is not the case for `constexpr` variables. They're the same in every file.

          4)
          Right. `const` variables can also be made to have a single memory location by declaring them `inline`. All `constexpr` variables are `inline` by default, that's why they do this.

          > how do I find all my comments?
          There's no friendly interface. You can use the wordpress api and run the result through a json beautifier to get a somewhat readable overview ( https://jsonbeautifier.org/?url=https%3A%2F%2Fwww.learncpp.com%2Fwp-json%2Fwp%2Fv2%2Fcomments%3Fper_page%3D100%26search%3Dhellmet ) (click on the little arrows on the right the expand the comments).

          • hellmet

            Thank you very much! That makes so much stuff clear!
            I really appreciate your patience and dedication in maintaining this site!
            I'll comeback someday, after I get a job and express my gratitude!

  • murat yilmaz

    In find this topic hard to understand.

    What is the difference between scope and linkage?

    What is the difference between global variables and external variables? (They have automatically the extern keyword)

    What is the difference between intern variables and global variables or functions with the keyword "static"?

    Why would you want to make variables only visible to that specific file by placing the static keyword?

    • potterman28wxcv

      > What is the difference between scope and linkage?

      The scope defines where you can use a given variable in the C++ code.

      Linkage is the process of linking several object (binary) files into one executable. In this process, each object file has a number of symbols that are defined - if you create a constant in your C++ code, your constant will have a symbol in the object file. However, if your constant is static, then that symbol will not be able to be used by the other object files - the "scope" of the symbol will be local to the object file corresponding to your C++ source file.

      I'm not sure how exactly does a symbol stay local to an object file. But the result is that the other object files won't be able to see your symbol. So if you use your constant (that was defined static) in another C++ source file, the corresponding object will use it as well, but when the linker tries to form one executable, it won't be able to link the symbol to its location.

      I don't know if it makes it more clear - you might want to re-read the chapter about the compilation process.

      > What is the difference between intern variables and global variables or functions with the keyword "static"?

      Global variables and functions (with or without the static keyword), will have a symbol attached to them by the compiler, in the object file. If you compile with the -S option (which stops at the assembly), and then read the generated assembly, you will see that your static identifiers have all been translated into a symbol (something that ends with a ':').

      On the other hand, intern variables won't have any symbol attached to them. And the compiler will decide whether the intern variable will reside in a processor register, or somewhere on the stack (in memory), or a combination of both. By the way, it is much more efficient to manipulate registers than it is to manipulate memory, so intern variables will always be more efficient than global variables.

      > Why would you want to make variables only visible to that specific file by placing the static keyword?

      It's a bit like a principle of encapsulation. You want to know where this or that variable is used. If there is no static keyword, then that variable could be used anywhere in your code - and if a bug happens related to that specific variable, then it will potentially be a lot harder for you to pinpoint where something went wrong.

      In the examples of these tutorials it's always easy because you never have more than 100 lines of code. On real life projects (even those that you do by yourself), your codebase can reach easily 1000+ lines of code, sometimes even 10000. Good luck trying to find what went wrong if you only use global variables - moreover if none of these global variables have the "static" keyword.

      Global variables have their uses - but you should avoid them whenever you can. Because it is much simpler to reason in terms of local variables that reside in 40-50 lines of code, rather than having to deal with variables shared by all the program, and that could be modified anywhere.

      I'm not sure about the 2nd question.

    • Alex

      > What is the difference between global variables and external variables? (They have automatically the extern keyword)

      Nothing, they are the same thing.

  • Abhinav

    I have a question regarding linkage and duration with respect to your example above. Global variables have static duration right? So the variables inside constants.cpp are destroyed when we leave that program right? So how come if I #include constants.h in my main.cpp file, I can access constants defined in constants.cpp, even though constants.cpp has ended executing (Or its not?) ?

    edit: Is my following understanding correct:
          1)global variables (file scope) have static duration, i.e
          destroyed when file finishes execution.
          2)extern variables (true global scope) do not have static
          duration but persist even after file execution completes.

    • Files don't execute, files only matter to your compiler, but not a runtime. Static variables die when the program ends.

      > global variables (file scope) have static duration
      Yes

      > destroyed when file finishes execution
      No

      > extern variables (true global scope) do not have static duration
      They have static duration

      > persist even after file execution completes
      There is no "file execution", they die when the program ends.

  • Vir1oN

    Hey @Alex
    I’ve just read the chapter for several times, and one thing remains unclear: what happens with external variables’ scope, when they are exported to another file? You wrote:

    “Global variables have global scope (aka. file scope), which means they can be accessed from the point of declaration to the end of the file in which they are declared.”

    As well as:

    “Global variables have global scope, and can be used anywhere in the program“

    Thus I make the conclusion that scope must be renewed or something, or how the variable can be accessed in the other files otherwise?

    Also it’s still a bit hard for me to understand the difference between the terms of “linkage” and “scope”. In the quiz solution you wrote:

    “Scope determines where a variable is accessible”
    “Linkage determines whether the variable can be exported to another file or not”

    But couldn’t the second sentence be rephrased as “ linkage determines whether the variable can be accessed from another file or not”? If so, linkage seems to be scope in the broader sense. Or I just don’t understand it correctly?

    • Alex

      When a global variable is defined, in the file for which it is defined, it can then be accessed from the point of definition to the end of the file.
      However, via a forward declaration, the variable can be used from other files (assuming external linkage), from the point of the forward declaration to the end of the file containing the forward declaration. The compiler doesn't know this is the same variable as in another file.

      Scope works file by file and is enforced by the compiler.
      Linkage works across files, and is enforced by the linker.
      Thus, in order to be accessed from another file, the variable must have external linkage (to satisfy the linker) AND it must be in scope (to satisfy the compiler).

  • Sweta

    It was my understanding from one of the previous topics that constexpr must be used for constants that are initialised during compile-time, and const must be used for constants that are initialised during run-time, yet the above example uses "const" for compile-time initialisation. Is there a particular reason for this?

    • Alex

      Const can be used for either runtime or compile-time constants.

      It's more precise to use constexpr if you can, but it's not necessary to update older code/examples that already work unless there's a specific reason to.

  • Louis Cloete

    @Alex, since you suggest that one namespace non-const global variables, maybe you should explain how to forward declare a namespaced global variable. It has not been obvious to me when I wanted to use a global Mersenne twister over multiple files for the game in chapter 11.x's quiz. I found out by trial and error after a lot of different errors about duplicate definition and undefined symbols that it is like this:

    foo.cpp:

    bar.cpp:

    • Alex

      Thanks for the feedback. There's an example in this very lesson already on how to do this -- perhaps it wasn't obvious enough. I've updated the comments in the example to make it more explicit that the forward declarations need to go in a namespace.

  • Alireza

    Hi and greeting,
    I'm using Qt Creator 4.7.
    I have written this code:

    however in mathematical.cpp file:

    it gives me this warning for both variables @g_pi and g_gravity :

    What do you suggest for it ?

    • Include mathematical.h in mathematical.cpp so it sees the declaration, or use inline variables.

      By using inline variable you don't need another source file, because inline variables are allowed to be defined multiple times.

  • _weedfox

    So if im working with only 1 file is it better to use static since it will be only used for this file anyway or let it be external since its easier and wont be used external anyway?

Leave a Comment

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