In lesson 6.3 -- Local variables, we said, “An identifier’s linkage determines whether other declarations of that name refer to the same object or not”, and we discussed how local variables have no linkage
.
Global variable and functions identifiers can have either internal linkage
or external linkage
. We’ll cover the internal linkage case in this lesson, and the external linkage case in lesson 6.7 -- External linkage.
An identifier with internal linkage can be seen and used within a single file, but it is not accessible from other files (that is, it is not exposed to the linker). This means that if two files have identically named identifiers with internal linkage, those identifiers will be treated as independent.
Global variables with internal linkage
Global variables with internal linkage are sometimes called internal variables.
To make a non-constant global variable internal, we use the static
keyword.
1 2 3 4 5 6 7 8 9 |
static int g_x; // non-constant globals have external linkage by default, but can be given internal linkage via the static keyword const int g_y { 1 }; // const globals have internal linkage by default constexpr int g_z { 2 }; // constexpr globals have internal linkage by default int main() { return 0; } |
Const and constexpr global variables have internal linkage by default (and thus don’t need the static
keyword -- if it is used, it will be ignored).
Here’s an example of multiple files using internal variables:
a.cpp:
1 |
constexpr int g_x { 2 }; // this internal g_x is only accessible within a.cpp |
main.cpp:
1 2 3 4 5 6 7 8 9 10 |
#include <iostream> static int g_x { 3 }; // this separate internal g_x is only accessible within main.cpp int main() { std::cout << g_x << '\n'; // uses main.cpp's g_x, prints 3 return 0; } |
This program prints:
3
Because g_x
is internal to each file, main.cpp
has no idea that a.cpp
also has a variable named g_x
(and vice versa).
For advanced readers
The use of the static
keyword above is an example of a storage class specifier, which sets both the name’s linkage and its storage duration (but not its scope). The most commonly used storage class specifiers
are static
, extern
, and mutable
. The term storage class specifier
is mostly used in technical documentations.
The one-definition rule and internal linkage
In lesson 2.6 -- 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 internal objects (and functions) that are defined in different files are considered to be independent entities (even if their names and types are identical), so there is no violation of the one-definition rule. Each internal object only has one definition.
Functions with internal linkage
Because linkage is a property of an identifier (not of a variable), function identifiers have the same linkage property that variable identifiers do. Functions default to external linkage (which we’ll cover in the next lesson), but can be set to internal linkage via the static
keyword:
add.cpp:
1 2 3 4 5 6 |
// This function is declared as static, and can now be used only within this file // Attempts to access it from another file via a function forward declaration will fail static int add(int x, int y) { return x + y; } |
main.cpp:
1 2 3 4 5 6 7 8 9 10 |
#include <iostream> int add(int x, int y); // forward declaration for function add int main() { std::cout << add(3, 4) << '\n'; return 0; } |
This program won’t link, because function add
is not accessible outside of add.cpp
.
Quick Summary
1 2 3 4 5 6 7 8 9 |
// Internal global variables definitions: static int g_x; // defines non-initialized internal global variable (zero initialized by default) static int g_x{ 1 }; // defines initialized internal global variable const int g_y { 2 }; // defines initialized internal global const variable constexpr int g_y { 3 }; // defines initialized internal global constexpr variable // Internal function definitions: static int foo() {}; // defines internal function |
We provide a comprehensive summary in lesson 6.11 -- Scope, duration, and linkage summary.
![]() |
![]() |
![]() |
Clarification :
if i dont use STATIC on a global non-constant variable it can be referenced in another file ?
if i have
add.cpp
int g_x{5};
main.cpp
std::cout << g_x ;
i can see the variable in main.cpp ?
QUESTION :
if we wanted a constant variable that is global with external linkage how do we do it ?
since all constant variables are internal.
Keep reading. This is answered in a couple of lessons.
Why do const objects have internal linkage by default?
Mainly so you can define them in a header file and #include them where you need them without running into problems with the one definition rule.
Ah, ok thanks.
Hello,
Should we favor the use of static keyword for functions within a file as much as possible for a bigger program? Is it considered good practice?
Hi!
Yes, if you don't intend on using a function outside of the current file, the function should be `static`.
Where should the `static` keyword go - header file, .cpp file or both? I ask this because I noticed that the compiler (i.e. Visual Studio) doesn't seem care.
If I've understood correctly, you should use the static keyword both for the definition in the .cpp file as well as the declaration in the .h file. This should ensure that if you #include your .h file, the linker doesn't complain about getting a mismatch in declaration and definition when you run your program. I am no expert though, so it's probably best to just try it out!
You don't separate `static` variables or functions into header and source files. `static` is used to give these entities internal linkage, ie. make them accessible only in the current _source file_. If you want something to be accessible across files, it must have external linkage (and not be `static`) or be `inline` and have internal linkage.
Ah, I see. So, if you don't want to use a symbol beyond a given translation unit, there is no point declaring it in a header file.
Correct
Lesson updated, thanks for the suggestion!
Thanks for this tutorial, very well explained!
Regarding "The one-definition rule and internal linkage" part.
Specifically this statement -
"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."
But what about "variable shadowing", isn't that more than one definition in a single file (program)?
I think in the situation of "variable shadowing", the two variables are not the same object, thus it does not break the one-definition rule.
Under the section titled Functions with Internal Linkage, the example given confuses me a bit. Shouldn't the code in main.cpp include the header file add.h? Otherwise, how does main.cpp potentially see anything in that header file? I know the point of the exercise is to make function add() static (internal) instead of the default external. Is there another way that main.cpp was "seeing" the add.cpp file without #including the code. I hope I'm making sense here....
You don't _need_ headers. There's no connection between a header and its source file. All a header does is provide forward declarations for the definitions in the source file. In the example you're referring to, we manually forward declared `add` in main.cpp. A header wouldn't have done anything different.
I saw "static" written after the "const" keyword. Like that:
Has this the same meaning with "static" written before "const"? Like that:
ps: I know that const variable has internal linkage by default, and no need for static anyway.
Yes, it's the same. C++ isn't very strict about where the `const` needs to go.
I am just trying to understand the difference between "int x" and "static int x" so i wrote the following code-
//Const.cpp
int x = 8;
//Internal.cpp
#include <iostream>
#include "Const.cpp"
int main()
{
std::cout << x << "\n";
}
In this case i get the following error
Error LNK1169 one or more multiply defined symbols found
But if I write the following-
//Const.cpp
static int x = 8;
//Internal.cpp
#include <iostream>
#include "Const.cpp"
int main()
{
std::cout << x << "\n";
}
Then it compiles.
This voilates "Internal global variables definitions"
Can you please help me with this?
Never include .cpp files. `x` is defined once in Const.cpp and then again in main.cpp.
Hello! I am loving these tutorials probably way more than I should lol XD . No seriously they helped me understand c++ better than I ever imagined. Thank you Alex and Nascardriver for the effort you put in these tutorials.
I wanted to ask if anyone knows a website for teaching HTML/CSS or python, I mean a website or an app or a youtube channel (it doesn't matter) that teaches those languages not just the syntax but also how and why those languages are the way they are and if possible they also show you the best practices and what not.
If there isn't though how can I know those stuff on my own? I mean the best practices and what to do and what not to do...
It's honestly sad I see no tutorials as good as yours guys that really focuses on the reader understanding the fundamentals and following best practices :(
Anyway enough with my rambling, please help if you know anything :)
For python youtube channels, I would recommend Sentdex and TechWithTim. For html/css, I'd recommend FreeCodeCamp.
Hi,
I have two questions:
1) "The most commonly used storage class specifier values are static, extern, and mutable."
I am not an advanced learner, but I am curious to know about it : does that sentence mean if we use any of those keyword with identifiers (static, or extern or mutable), we refer to them as "storage class specifier"?
2) Is this use of 'static' here different from 'static' used for instance variables of a class in Object Oriented?
The meaning of `static` depends on the context. It can be used as a storage specifier, to cause internal linkage, and to declare instance-less members. You've seen the first 2 already, we show the third version later.
"Because linkage is a property of an identifier (not of a variable), functions have the same linkage property that variables do. "
Should this be rephrased to:
"Because linkage is a property of an identifier (not of a variable), functions have the same linkage property that identifiers do."
Updated. Thanks!
How does this interact with #include? For example if I have
would then mps and mpss each utilize their own ever lasting copy of g so that the purpose of having that g centralised is defeated because it's stored twice? (I'm guessing that the better solution would be to have it in a constants namespace).
Each get their own `g`. Making `g` `inline` solves this.
It's though technically different than having one g with external linkage, right? The effect of using inline is that occurrences of g in mps and mpss are treated at compile time as if they were the literal "9.8". So in that case there's never even allocated memory for the double g.
Nope, "inline" is a misleading name. It doesn't mean that `inline` functions/variables get inlined (though, they might). `inline` variables don't have to be `const` either, you can reassign values during run-time.
`constexpr` variables are closer to what you've explained. Their value can be computed at compile-time, so it's likely they disappear during compilation.
Thanks for the clarification. I looked up the inline specifier and it looks like this: if you declare something `inline constexpr` it's given external linkage and the permission to multiple definitions. Thus it may or may not be optimized away due to either of `inline` or `constexpr` but if it is not optimized away then at least it's only allocated once. Pre cpp17 you could either (as said in the lecture) declare it as const and external and define it once (where it would most surely wouldn't get optimized away and allocated once) or define it multiple times as internal and constexpr (where it most surely would be optimized away but allocated multiple times if the optimisation failed). I only was unsure if it's given external linkage in the case of `inline constexpr` declaration by default and indeed: "Inline const variables at namespace scope have external linkage by default (unlike the non-inline non-volatile const-qualified variables)". Says the reference. Quite possible you said that in the lecture already and I missed it.
I was thinking that till now that warnings are actually legit errors in main code that program would ignore to compile if "Treat warnings as errors" was disabled. Thanks for clearing my doubt @nascardriver
Hello where did you find that? I don't that option when I press properties>general please help :(
Under "Functions with internal linkage", if i add
int add(int x, int y)
{
return x - y;
}
to main.cpp and remove int add(int x, int y); then i get this error.
Source.cpp(1,12): error C2220: the following warning is treated as an error
Source.cpp(1,12): warning C4505: 'add': unreferenced local function has been removed
why is that? since add.cpp has a static function, the program should auto ignore the function in add.cpp and compile without any problem right ? But it behaves differently here.
You're not getting an error as a violation of a language rule.
You're getting an error because you got a warning and your treating warnings as errors.
You're getting a warning as a friendly reminder from the compiler that you wrote a function but you're never using it (`add` in "add.cpp").
The code is fine, but you made a mistake, and you told your compiler not to let you make mistakes. If you want to compile the code anyway, you can temporarily disable "Treat warnings as errors" (or similar) in your project settings.