7

I understand that there are three possible linkage values for a variable in C++ - no linkage, internal linkage and external linkage.

So external linkage means that the variable identifier is accessible in multiple files, and internal linkage means that it is accessible within the same file. But what is the point of internal linkage? Why not just have two possible linkages for an identifier - no linkage and external linkage? To me it seems like global (or file) scope and internal linkage serve the same purpose.

Is there any use case where internal linkage is actually useful that is not covered by global scope?

In the below example, I have two pieces of code - the first one links to the static int i11 (which has internal linkage), and the second one does not. Both pretty much do the same thing, since main already has access to the variable i11 due to its file scope. So why have a separate linkage called internal linkage.

static int i11 = 10;

int main()
{
extern int i11;
cout << ::i11;
return 0;
}

gives the same result as

static int i11 = 10;

int main()
{
 cout << ::i11;
 return 0;
}

EDIT: Just to add more clarity, as per HolyBlackCat's definition below, internal linkage really means you can forward-declare a variable within the same translation unit. But why would you even need to do that for a variable that is already globally accessible within the file .. Is there any use case for this feature?

SR Bhaskar
  • 898
  • 7
  • 17
  • 1
    If the variable had no linkage, you would not be able to access it at all. –  Jan 11 '18 at 23:12
  • 2
    External linkage is for when you have multiple .c (or .cpp) files (not included files, those count as part of the .c file that includes them), that you want to compile separately from each other. – Cpp plus 1 Jan 11 '18 at 23:12
  • 1
    [This.](https://stackoverflow.com/a/47343416/2752075) I may be mistaken, but 'no linkage' seems to mean 'can't be forward declared'. – HolyBlackCat Jan 11 '18 at 23:16
  • 1
    Why do you think the second snippet demonstrates a different linkage? – HolyBlackCat Jan 11 '18 at 23:17
  • HolyBlackCat - yes 'no linkage' seems to mean 'cannot be forward declared'... and internal linkage seems to mean 'can be forward declared within a translation unit'-- my question is why would we even need to forward declare a variable within the translation unit where it is already accessible globally? – SR Bhaskar Jan 11 '18 at 23:23
  • 1
    This may be useful for a ring of static functions calling each other, and probably is allowed for variables just because there is no reason to disallow that. – HolyBlackCat Jan 11 '18 at 23:26
  • HolyBlackCat - I was stating that the second snippet simply does not use the Internal Linkage feature of i11, while the first snippet does. – SR Bhaskar Jan 11 '18 at 23:31
  • No linkage is basically unique to local variables (including static locals). If you want to have a variable that is global to the translation unit, but not the program, you need internal linkage. I'm not really sure what the confusion is? – Nir Friedman Jan 12 '18 at 00:43

2 Answers2

11

Examples of each:

External linkage:

foo.h

    extern int foo; // Declaration

foo.cpp

    extern int foo = 42; // Definition

bar.cpp

    #include "foo.h"

    int bar() { return foo; } // Use

Internal linkage:

foo.cpp

    static int foo = 42; // No relation to foo in bar.cpp


bar.cpp

    static int foo = -43; // No relation to foo in foo.cpp

No linkage:

foo.cpp

    int foo1() { static int foo = 42; foo++; return foo; }
    int foo2() { static int foo = -43; foo++; return foo; }

Surely you will agree that the foo variables in functions foo1 and foo2 have to have storage. This means they probably have to have names because of how assemblers and linkers work. Those names cannot conflict and should not be accessible by any other code. The way the C++ standard encodes this is as "no linkage." There are a few other cases where it is used as well, but for things where it is a little less obvious what the storage is used for. (E.g. for class you can imagine the vtable has storage, but for a typedef it is mostly a matter of language specification minutiae about access scope of the name.)

C++ specifies somewhat of a least common denominator linkage model that can be mapped onto the richer models of actual linkers on actual platforms. In practice this is highly imperfect and lots of real systems end up using attributes, pragmas, or compiler flags to gain greater control of linkage type. In order to do this and still provide a reasonably useful language, one gets into name mangling and other compiler techniques. If C++ were ever to try and provide a greater degree of compiled code interop, such as Java or .NET virtual machines do, it is very likely the language would gain clearer and more elaborate control over linkage.

EDIT: To more clearly answer the question... The standard has to define how this works for both access to identifiers in the source language and linkage of compiled code. The definition must be strong enough so that correctly written code never produces errors for things being undefined or multiply defined. There are certainly better ways to do this than C++ uses, but it is largely an evolved language and the specification is somewhat influenced by the substrate it is compiled onto. In effect the three different types of linkage are:

  • External linkage: The entire program agrees on this name and it can be access anywhere there is a declaration visible.
  • Internal linkage: A single file agrees on this name and it can be accessed in any scope the declaration is visible.
  • No linkage: The name is for one scope only and can only be accessed within this scope.

In the assembly, these tend to map into a global declaration, a file local declaration, and a file local declaration with a synthesized unique name.

It is also relevant for cases where the same name is declared with different linkage in different parts of the program and in determining what extern int foo refers to from a given place.

Zalman Stern
  • 3,161
  • 12
  • 18
-1

External linkage is for when you have files being compiled independently of each other (#included .h, .c, and .cpp files are not compiled independently of each other). An extern variable is special in that it can be used between files being compiled separately.

Cpp plus 1
  • 990
  • 8
  • 25
  • OP already said that in the second paragraph. The real question is 'no linkage vs static linkage'. – HolyBlackCat Jan 11 '18 at 23:19
  • @HolyBlackCat OP said "multiple files", by which he seems to mean included files. I don't think he would be asking the question if he knew external variables can be used in separate compilation units. – Cpp plus 1 Jan 11 '18 at 23:20
  • Still, the post has some other questions. Maybe this should be a comment?.. – HolyBlackCat Jan 11 '18 at 23:26