6.6 — Internal linkage

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.

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:



This program prints:


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 specifier values 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.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 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:



This program won’t link, because function add is not accessible outside of add.cpp.

Quick Summary

We provide a comprehensive summary in lesson 6.11 -- Scope, duration, and linkage summary.

6.7 -- External linkage
6.5 -- Variable shadowing (name hiding)

12 comments to 6.6 — Internal linkage

  • sami

    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?

    • nascardriver

      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.

  • Tepy

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

  • Abraxasknister

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

    • nascardriver

      Each get their own `g`. Making `g` `inline` solves this.

      • AbraxasKnister

        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.

        • nascardriver

          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.

          • AbraxasKnister

            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.

  • kavin

    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

  • kavin

    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.

    • nascardriver

      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.

Leave a Comment
