1

The C++11 standard give the code snippet below (I deleted unrelated code) and said the name i have external linkage. (clause 3.5.6)

static int i = 0; // #1
void g() {
    extern int i; // #3 external linkage
}

Why do they do this? Did I misunderstand something? The two i refer to the same object in vs2012. And when I use i somewhere else, i got an unresolved external error. I have no idea whether vs2012 support this feature or not.

Edit: I think VS2012 is doing the right thing. The i in #3 only need to refers to an i that has a linkage. If the compiler can't find one, than the i should be defined in other translation unit. So the two i should refer to the same object in the code snippet above.

The quote from the standard:

If there is a visible declaration of an entity with linkage having the same name and type, ignoring entities declared outside the innermost enclosing namespace scope, the block scope declaration declares that same entity and receives the linkage of the previous declaration. if no matching entity is found, the block scope entity receives external linkage.

But why people need this feature?

  • 1
    This is not the example from IS C++11 §3.5p6. The actual example contains an additional block-scope `int i;`, which is the reason why the `extern int i;` in the actual example has *external* instead of *internal* linkage. – dyp Jun 08 '15 at 17:18
  • @dyp, the additional block in the example does not change the linkage of the second `i`. please look at the accepted answer once more. – neonxc Nov 07 '19 at 12:31
  • and the reason they introduced a new block in the standard is explained in the [answers here](https://stackoverflow.com/questions/45724358/error-extern-declaration-of-i-follows-declaration-with-no-linkage). – neonxc Nov 07 '19 at 12:39
  • @neonxc The linked answer is about the C programming language. I believe this is a case where C and C++ differ. [This is the example from the C++11 Standard](https://godbolt.org/z/sF3tqY) compiled as C -- it is rejected. But the Standard states it is legal C++ and the `extern int i;` variable has extern linkage. It does not *change* the linkage of the `static int i = 0;` at namespace scope, it rather declares a *different* entity. Btw the same example is illegal under current C++ rules. [to be continued] – dyp Nov 07 '19 at 18:31
  • @neonxc C++11: *"If there is a visible declaration of an entity with linkage having the same name and type, ignoring entities declared outside the innermost enclosing namespace scope, the block scope declaration declares that same entity and receives the linkage of the previous declaration."* However the additional block-scope `int i;` in the C++11 example (see link above) *hides* the namespace-scope `static int i = 0;`. Therefore the `extern int i;` does not refer to the same object. In newer revisions of C++, this has been made illegal (same name internal+external link in same TU). – dyp Nov 07 '19 at 18:34

3 Answers3

7

#3 is only a declaration; it states that a variable called i exists somewhere in the program, with external linkage, but does not define that variable. The declaration allows you to use that, rather than the static variable from #1, within the scope of g.

You will also need to define it, in the namespace that contains g. In this case, it will have to be in a different translation unit, so that it doesn't conflict with the static variable with the same name.

To be clear, there are two different variables called i here, as explained in the paragraph following the example. #1 is defined here; #3 is only declared, and needs a separate definition.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • But actually the two `i` refer to the same object (at least in vs2012). –  Apr 16 '13 at 14:41
  • If that is the case, then the compiler is wrong. The paragraph following the example clearly explains that they are separate. It begins "There are three objects named `i` in this program." – Mike Seymour Apr 16 '13 at 14:45
  • 1
    @Mike (OP) You said VS2012 complains about an unresolved symbol (namely the `i` with external linkage). That means those are **not** the same `i`. – huskerchad Apr 16 '13 at 14:47
  • @huskerchad I mean I got that error if I use the name somewhere else. –  Apr 16 '13 at 14:49
  • this does not sound to me like an explanation for why `i` has external linkage even though it was defined to have internal linkage at `#1`. what's the rationale? – Johannes Schaub - litb Apr 16 '13 at 14:52
  • @JohannesSchaub-litb: There are two variables called `i`; one with internal linkage defined at `#1`, and one with external linkage declared at `#3` but not defined in the example. – Mike Seymour Apr 16 '13 at 15:06
  • @MikeSeymour How can I define another `i` in the namespace that contains `g` when there is already a static `i`. –  Apr 16 '13 at 15:07
  • @Mike: As I said in the answer, you'll have to do that in a different translation unit. – Mike Seymour Apr 16 '13 at 15:08
  • @MikeSeymour I did it. But `i` still refers to the static one. T﹏T I have no other compiler to try. –  Apr 16 '13 at 15:11
  • this clearly violates the rules given in 3.3.1p4, doesn't it? because both `i`, the visible and the invisible name, do *not* refer to the same entity. – Johannes Schaub - litb Apr 16 '13 at 15:20
  • @JohannesSchaub-litb: I'm out of my depth there; I'm just answering the question that was asked, not trying to figure out whether the C++ standard is self-consistent. – Mike Seymour Apr 16 '13 at 15:52
  • the outer `i` has the same name and type and has linkage (internal). so the standard requires the local `extern` declaration to have internal linkage aswell and declare the same entity, doesn't it? why not? – Johannes Schaub - litb Apr 16 '13 at 15:54
  • @JohannesSchaub-litb: OK, I've read it in more detail now. 3.3.1p4 describes "a set of declarations in a single declarative region", while in the example they are declared in different regions (the function, and the surrounding namespace). So, by my interpretation, there's no violation of any rules here, any more than there would be if `#3` were automatic or static. But this comment isn't the place for answering questions; if you want answers, ask a separate question. – Mike Seymour Apr 16 '13 at 16:11
  • @MikeSeymour the note after the paragraph explicitly says that *"These restrictions apply to the declarative region into which a name is introduced, which is not necessarily the same as the region in which the declaration occurs."*. We must differentiate declarations as syntactic constructs and as a semantic action. The semantic action is the introduction (or re-introduction) of a name, which is what is being constrained here. – Johannes Schaub - litb Apr 16 '13 at 17:11
  • @MikeSeymour it was a rhetoric question of sorts :) – Johannes Schaub - litb Apr 16 '13 at 17:18
2
static int i = 0; // #1
void g() {
    extern int i; // #3 external linkage
}

The first static i is a declaration and is visible only in the current source file.

extern int i; 

tells the compiler I don't mean this static i but another i defined somewhere else. If you haven't defined it somewhere else (in another translation unit) you will get the undefined reference.

And this doesn't break the ODR because this (the static) i is static (visible only in this unit).

stardust
  • 5,918
  • 1
  • 18
  • 20
1
extern int i;

Promises compiler I will give you an int i.

The static int i=0; is not that promised variable, and you have to declare a int i somewhere else visible to that extern variable declaration.

In other words extern int i; and static int i=0; are two irrelevant variables.

masoud
  • 55,379
  • 16
  • 141
  • 208