The concepts of scope, duration, and linkage cause a lot of confusion, so we’re going to take an extra lesson to summarize everything. Some of these things we haven’t covered yet, and they’re here just for completeness / reference later.
Scope summary
An identifier’s scope determines where the identifier can be accessed within the source code.
- Variables with block scope / local scope can only be accessed within the block in which they are declared (including nested blocks). This includes:
- Local variables
- Function parameters
- User-defined type definitions (such as enums and classes) declared inside a block
- Variables and functions with global scope / file scope can be accessed anywhere in the file. This includes:
- Global variables
- Functions
- User-defined type definitions (such as enums and classes) declared inside a namespace or in the global scope
Duration summary
A variable’s duration determines when it is created and destroyed.
- Variables with automatic duration are created at the point of definition, and destroyed when the block they are part of is exited. This includes:
- Local variables
- Function parameters
- Variables with static duration are created when the program begins and destroyed when the program ends. This includes:
- Global variables
- Static local variables
- Variables with dynamic duration are created and destroyed by programmer request. This includes:
- Dynamically allocated variables
Linkage summary
An identifier’s linkage determines whether multiple declarations of an identifier refer to the same identifier or not.
- An identifier with no linkage means the identifier only refers to itself. This includes:
- Local variables
- User-defined type definitions (such as enums and classes) declared inside a block
- An identifier with internal linkage can be accessed anywhere within the file it is declared. This includes:
- Static global variables (initialized or uninitialized)
- Static functions
- Const global variables
- Functions declared inside an unnamed namespace
- User-defined type definitions (such as enums and classes) declared inside an unnamed namespace
- An identifier with external linkage can be accessed anywhere within the file it is declared, or other files (via a forward declaration). This includes:
- Functions
- Non-const global variables (initialized or uninitialized)
- Extern const global variables
- Inline const global variables
- User-defined type definitions (such as enums and classes) declared inside a namespace or in the global scope
Identifiers with external linkage will generally cause a duplicate definition linker error if the definitions are compiled into more than one .cpp file (due to violating the one-definition rule). There are some exceptions to this rule (for types, templates, and inline functions and variables) -- we’ll cover these further in future lessons when we talk about those topics.
Also note that functions have external linkage by default. They can be made internal by using the static keyword.
Variable scope, duration, and linkage summary
Because variables have scope, duration, and linkage, let’s summarize in a chart:
Type | Example | Scope | Duration | Linkage | Notes |
---|---|---|---|---|---|
Local variable | int x; | Block | Automatic | None | |
Static local variable | static int s_x; | Block | Static | None | |
Dynamic variable | int *x { new int{} }; | Block | Dynamic | None | |
Function parameter | void foo(int x) | Block | Automatic | None | |
External non-constant global variable | int g_x; | File | Static | External | Initialized or uninitialized |
Internal non-constant global variable | static int g_x; | File | Static | Internal | Initialized or uninitialized |
Internal constant global variable | constexpr int g_x { 1 }; | File | Static | Internal | Must be initialized |
External constant global variable | extern constexpr int g_x { 1 }; | File | Static | External | Must be initialized |
Inline constant global variable | inline constexpr int g_x { 1 }; | File | Static | External | Must be initialized |
Internal constant global variable | const int g_x { 1 }; | File | Static | Internal | Must be initialized |
External constant global variable | extern const int g_x { 1 }; | File | Static | External | Must be initialized at definition |
Inline constant global variable | inline const int g_x { 1 }; | File | Static | External | Must be initialized |
Forward declaration summary
You can use a forward declaration to access a function or variable in another file:
Type | Example | Notes |
---|---|---|
Function forward declaration | void foo(int x); | Prototype only, no function body |
Non-constant global variable forward declaration | extern int g_x; | Must be uninitialized |
Const global variable forward declaration | extern const int g_x; | Must be uninitialized |
Constexpr global variable forward declaration | extern constexpr int g_x; | Not allowed, constexpr cannot be forward declared |
What the heck is a storage class specifier?
When used as part of an identifier declaration, the static
and extern
keywords are called storage class specifiers. In this context, they set the storage duration and linkage of the identifier.
C++ supports 4 active storage class specifiers:
Specifier | Meaning | Note |
---|---|---|
extern | static (or thread_local) storage duration and external linkage | |
static | static (or thread_local) storage duration and internal linkage | |
thread_local | thread storage duration | Introduced in C++11 |
mutable | object allowed to be modified even if containing class is const | |
auto | automatic storage duration | Deprecated in C++11 |
register | automatic storage duration and hint to the compiler to place in a register | Deprecated in C++17 |
The term storage class specifier is typically only used in formal documentation.
![]() |
![]() |
![]() |
in "Variable scope, duration, and linkage summary"
is there such a thing as "Inline non-constant global variable" ?
Variables with static duration are created when the program begins and destroyed when the program ends.
This includes:
Global variables
Static local variables
what does this mean ? does it mean if i have a function with a static variable, when the function ends the variable still exists ?
void foo()
{
static int x{2};
} // x is not destroyed ?
int main()
{
foo();
return 0;
}
Yes.
Thanks for the summary! I wrote a program to help remember the tables' contents: https://pastebin.com/V6DC5BwP
A few tips:
1.
Variable scope, duration, and linkage summary:
- the const variables appear after the constexpr variables
Forward declaration summary:
- the constexpr variables appear after the const variables
I think you should switch const and constexpr in one of them.
2.
Variable scope, duration, and linkage summary:
- I think you should add an empty line before row 7 and another before row 10. This will make the table look less overwhelming, as it would be split into 3 parts (variables with block scope, const variables and constexpr variables).
3. According to [this comment](https://www.learncpp.com/cpp-tutorial/the-auto-keyword/#comment-460178), you're in the process of removing all instances of "added in C++11". The last table contains two such instances.
4. Unrelated to this lesson:
Do any of you use alternative keyboard layouts (like Dvorak)? Dvorak apparently makes typing much less tiring, but I don't know if it works well with C++'s syntax.
In the "Variable scope, duration, and linkage summary" table, I believe "constant" in rows 7-9 should say "constexpr". i.e. "Internal constant global variable" should say "Internal constexpr global variable", since the former is included in the following rows.
Thanks
Some feedback.
1. The Variable Scope Summary seems more useful in Chapter 1.4 Variable assignment and initialization.
2. The Forward Declaration Summary seems more useful in Chapter 2.7 Forward Declarations and Definitions.
It would be nice to have the tables early and have a little checkboxes to know which part has been covered.
All the parts that were covered, check. If they have yet to be covered, empty.
That way, there's a systematic table/index that lets you know what is being covered and what you can expect in later chapters.
It's kind of difficult to follow with a table if it keeps jumping around. Like spaghetti code.
Cool tutorial. Very appreciated! :)
P.S.: How do you delete a comment?
hi . whats your mean "static storage duration"?
is your mean the static keyword?
See the table in section "Variable scope, duration, and linkage summary". Everything where it says "Static" in the "Duration" column has static storage duration.
A company header file was recently changed from defining a set of function prototypes to defining a set of function pointers. One source file sets the pointer and another file calls the function pointed to by it. All source files that include this header get the function pointer declarations without any "extern", so I figured at link time there should be a collision with several source files each claiming to define these function pointers; however, somehow it just seems to work (compiled and linked using g++ on Linux). I always assumed one file should define a global variable and others should specify extern, but this seems to be working - how? Does the linker resolve such conflicts somehow so that all references point to the same memory location? What if they had all specified a different initialization value?
In this phrase of yours
"When used as part of an identifier declaration, the static and extern keywords are called storage class specifiers."
shouldn't you say identifier's definition because
e.g.
main.cpp
[/code]
static int var; //definition(as well as declaration)
extern const var1; //forward declaration
.........
[/code]
here :-
static keyword only sets the linkage and duration of the variable 'var' but extern here forward declaring the const var only tells the compiler about its linkage it actually doesnt set its linkage .
Why in the table "Variable scope, duration, and linkage summary", there not any global variable defined using "const" keyword?
I added global `const` variables. Thanks for pointing out the omission!
Hi,
Does it mean when a class or enum is defined inside a function?
"User-defined type definitions (such as enums and classes) declared inside a block"
Any kind of block, eg. struct, function, if, namespace
Hello,
Can you please explain why constexpr variables cannot be forward declared ?
if you have some questions, you can try to search in stackOverflow, the best plateform for me.you just need to to search your question to find an other questions like this to resolve your question. (sorry for my eng)
I just tap and replace :
Hello,
Can you please explain why constexpr variables cannot be forward declared ? to "why constexpr variables cannot be forward declared stackOverflow" in your browser.
https://stackoverflow.com/questions/33197817/forward-declare-a-constexpr-variable-template
i know im the best :).
string literals also have static storage duration - https://en.cppreference.com/w/cpp/language/string_literal
From the linkage definition under summary:
" An identifier’s linkage determines whether multiple instances of an identifier refer to the same identifier or not "
What is meant by "instance" of an identifier? Is it the occurrences of the identifier ? Say for variable name "length", is every occurrence of the word "length" in a file an instance? Or do you mean only declarations of variable with name "length" ?
I changed "instances" to "declarations".
In the Linkage summary section under the third bullet point, you wrote "An identifier*s* with external linkage...". I suppose you meant "An identifier with external linkage...".
Typo fixed, thanks!
Just a small typo you might want to fix for readability.
In the Linkage summary section under the external linkage bullet,
you have "(such as enums and and classes)"
I think you meant "(such as enums and classes)"
Hi,
I may be dumb, but in the linkage summary it's said that static functions are covered in chapter 7, but I can't see where it is and don't remember learning about them (except for member static functions, which I suppose are a totally different thing and they are covered later). Can anyone point me in the right direction?
Hmmm, I think I actually don't cover these explicitly. I've removed the reference to chapter 7.
But just like static global variables, static functions are only accessible in the file in which they are declared.
There's a brief explanation (with an example) of static functions in lesson S.4.2 — Global variables and linkage (paragraph 'Function linkage'), it could be used as a reference instead (as a little refresher).
Thanks!
Hello!
On the end of the course, you've said that when we make forward declaration of a constant global variable in order to use it in another file, it should not be initialized. Shouldn't we initialize all constant variables in the moment of definition? What should I use if I want a constant global variable with external linkage and I want it to be initialized during definition?
Thank you!
Forward declarations just tell the compiler that an object (or function) exists (and what type it is). They don't define actual objects, and so they can't have initializers.
The actual defined object (that the forward declaration is referencing) should be initialized.
Wait, what's the scope of this article?
"Identifiers with external linkage will generally cause a duplicate definition linker error if the definitions are compiled into more than one .cpp file (due to violating the one-definition rule)."
Would you mind explaining this sentence? What does "if the definitions are compiled into more than one .cpp file"?
gabe.hpp
gabe.cpp
main.cpp
`gabe` is now defined in "gabe.cpp" and "main.cpp" (Because `#include` simply copies a file's content). Variables with external linkage can only be defined once, so you're getting and error.
How to prevent this from happening?
gabe.hpp
gabe.cpp
[/CODE]
#include "gabe.hpp"
// Define in a source file
int gabe{};
[/CODE]
Hi, Alex and Nascardriver!
What is normal function? I confused the term 'normal'. So, are there functions those are not normal?
Normal functions are the kind of functions we've presented so far. There are other kinds of functions (member functions, inline functions, etc...) that you'll learn about later.
Thank you, Alex!
What is the scope, duration, and linkage of namespace?