6

I have a few questions about the linkage from the following variables. By examples of 7.1.1/7 of C++03 and experimenting with compilers (Comeau, Clang and GCC), I came to the following linkage kinds:

  1. First static, then extern

    static int a; // (a)
    extern int a; // (b) valid, 'a' still internal
    

    It's clear to me with accordance to section 3.5: (a) implies internal linkage. And (b) also implies internal linkage, because the name "a" is declared static (by (a)).

  2. First extern, then static

    extern int b; // (c)
    static int b; // (d) invalid!
    

    First, (c) implies external linkage. But (d) implies internal linkage because the name "b" is declared static by (d). This is invalid according to 7.1.1/7, since the linkage implied is not consistent.

  3. First const, then extern

    const double pi1 = 3.14; // (e)
    extern const double pi1; // (f) valid and 'pi1' is internal
    

    First, (e) implies internal linkage, because it is const, and neither declared explicit extern nor previously implied external linkage. And (f) should imply extern linkage and be an error, because it explicitly declares the name extern, but the compilers keep it internal! Why so? That's my question.

  4. First extern, then const

    extern const double pi2; // (g)
    const double pi2 = 3.14; // (h) valid and 'pi2' is external
    

    Now, (g) implies external linkage because we explicitly declared extern. And (h) also implies external linkage because (g) explicitly declared extern.


I have experimentally found out the linkage for 3 and 4 with the following template (the second argument is required to have external linkage)

template<typename T, T&> struct ensure { };

ensure<const double, pi1> e1; // failed
ensure<const double, pi2> e2; // succeeded

Summary: The Discussion with Charles Bailey turned out to be quite fruitful and showed there are two possible interpretations of 3.5/3, where the important bullet point reads

A name having namespace scope (3.3.5) has internal linkage if it is the name of

  • an object or reference that is explicitly declared const and neither explicitly declared extern nor previously declared to have external linkage;

If we look at point (f), then the two interpretations come to different conclusions, as shown below

  1. The first interpretation notes that pi1 is declared const but is also declared extern. The variable has thus external linkage.

  2. The second interpretation interpretes both occurences of "declared" to refer to the same declaration. In this way, it means that it is declared const, but not extern const. We note that (e) is declared const and not extern const, thus we give pi1 internal linkage.

Now what interpretation is correct? I can't determine from that wording, but compilers seem to interpret this the second way. In particular, if we take the first interpretation, then the last quoted part of 3.5/3 would be superfluous, because there would be no valid scenario in which a name would be declared const and previously declared with external linkage but without an explicit extern.

Community
  • 1
  • 1
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    Maybe I'm missing something, but is 3 not the same as 1? (That is, the name `pi1` is 'declared static' so-to-speak?). Though I suppose I just begged the question why 4 is not invalid. – GManNickG Aug 21 '10 at 20:41
  • @GMan, See 3.5/3 for these two cases. They are handled by different bullet points. – Johannes Schaub - litb Aug 21 '10 at 20:42
  • @GMan for 4, the first made it external and the second doesn't make it internal, because the name was declared explicitly external (by the first declaration). So both only the first, as well as the first and second together imply the same linkage. For 2, only the first implies external linkage, but the first and second together imply internal linkage because the name is explicitly declared static by the second. Thus it's invalid. – Johannes Schaub - litb Aug 21 '10 at 20:51
  • I'm having a really hard time figuring your question out. What's this '#a' and '#b' stuff you're referring to? What's the 3.5 in 'with accordance to 3.5'? – Omnifarious Aug 21 '10 at 21:02
  • @Omnifarious, sorry. The `#a` stuff is just to reference those lines in the code. `3.5` is a C++ Standard section number. – Johannes Schaub - litb Aug 21 '10 at 21:07
  • @Johannes: Ah, got it, right. I'll see if I can summon an answer up in a moment. :) – GManNickG Aug 21 '10 at 21:34
  • @Omnifarious, i have prettified the code. – Johannes Schaub - litb Aug 21 '10 at 23:17
  • @litb: I also don't understand why you don't think 3 isn't essentially the same as 1. `const double pi1 = 3.14;` means that `pi1` has internal linkage. `extern const double pi1;` doesn't change the linkage. If you think it does imply a different linkage under which rule? As far as I can see it matches 3.5/4 "... has external linkage ... - an object [...], unless it has internal linkage", i.e. it would have meant external linkage except the name already has internal linkage which is OK. – CB Bailey Aug 21 '10 at 23:45
  • @Charles as i understand it, the rule for linkage of `pi1` is: It is external if it is not internal, and it is internal if "it's the name of an - object [...] that is explicitly declared static or - an object [...] that is explicitly declared const and neither explicitly declared extern nor previously declared to have external linkage". `pi1` is explicitly declared `extern`, thus it has no internal linkage, thus it has external linkage. – Johannes Schaub - litb Aug 21 '10 at 23:53
  • But `pi1` _is_ the name of an object the has just the previous line been explicitly declared `const` and neither explicitly declared `extern` not previously declared to have external linkage? – CB Bailey Aug 22 '10 at 00:00
  • @Charles `pi1` is declared on both lines. And in the second line, it is explicitly declared `extern`. – Johannes Schaub - litb Aug 22 '10 at 00:04
  • I'm really not getting this. Can you explain how you think that `static int i; extern int i;` is valid. Looking at the second declaration alone, it doesn't match any case that would give it internal linkage (3.5/3), so it _would_ have external linkage (3.5/4) except that the name already has internal linkage. How is the `const` then `extern const` case any different? – CB Bailey Aug 22 '10 at 00:10
  • @Charles, we don't look at only one declaration. But at all declarations. So we would find it is explicitly declared `static` and thus has internal linkage. This is in line when we would remove the second declaration (`i` would still have internal linkage), thus it is valid. With the `const`, we again look at all declarations, and we end up seeing the explicit `extern` of the second declaration, and so end up not giving it internal linkage. – Johannes Schaub - litb Aug 22 '10 at 00:15
  • Do you mean "this and all previous declarations" rather than "all declarations" because you seem to agree with the difference in handling of `static int a; extern int a;` and `extern int b; static int b;`? – CB Bailey Aug 22 '10 at 00:22
  • OK, in that case I think that I just don't agree with your interpretation. I believe that the handling `extern const double pi1;` is the same as `extern int a`. Is `pi1` the name of an object that is explicitly declared `const` and neither explicitly declared `extern` nor previously declared to have external linkage? Why yes (e) is where it is so declared. Sure, it's not declared in a way that matches that paragraph everywhere but (IMHO) it doesn't need to be. I think that this is where you don't agree with me? – CB Bailey Aug 22 '10 at 00:30
  • I think you may have editing your comment at the same time that I was typing mine... time for us to slow down and read, perhaps. – CB Bailey Aug 22 '10 at 00:31
  • OK, you convinced me to alter how to interpret 3.5/3 and 3.5/4 together. Previously I was looking at one declaration at a time but using "unless it has internal linkage" as a reason to peek at any already determined linkage. Now I look at the current and previous declarations together but still come to a different conclusion. – CB Bailey Aug 22 '10 at 00:38
  • @Charles yes that is where i don't agree i suspect. But I see now that this is IMHO very ambiguous. I didn't see that quite as clear as now. – Johannes Schaub - litb Aug 22 '10 at 00:38
  • I thought it was unambiguous too. Clearly, I was wrong! – CB Bailey Aug 22 '10 at 00:40
  • +1 for telling us how you found out the linkage – Chubsdad Aug 22 '10 at 02:04

3 Answers3

4
const double pi1 = 3.14; // (e)
extern const double pi1; // (f) valid and 'pi1' is internal

My interpretation is as follows. When considering the linkage of a name we consider previous declarations as well as the one being interpreted at this point in the parse. This is why static int a; extern int a; is OK, but extern int b; static int b; is not.

On encountering the first declaration we note that pi1 is explicitly declared const but neither explicitly declared extern nor previously declared to have external linkage. This matches one of the options of 3.5/2 therefore pi1 has internal linkage.

On encountering the second declaration we ask is pi1 the name of an object that is explicitly declared const but neither explicitly declared extern nor [... blah ...]. I contend that it is because it was so declared at point (e). Sure, it isn't declared that way everywhere but in the same way a was the name of an object declared static when we were considering the extern int a; declaration even though it wasn't declared static everywhere. This, to me, means that the declaration (f) doesn't imply a different linkage from declaration (e).

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • I think your interpretation makes sense. I think now what the Standard says is that it is explicitly declared const, but not "extern const". Because otherwise the later text "nor previously declared to have external linkage;" would be superfluous: The declaration that uses "const" but no "extern" will be a definition, but to be well-formed, any other declaration will *have* to use `extern` then. Only in the "extern const" interpretation, which you do apply i think, is the additional text not superfluous. – Johannes Schaub - litb Aug 22 '10 at 01:49
  • I've changed my question to summarize our findings, and I'm going to accept this one. – Johannes Schaub - litb Aug 22 '10 at 13:25
0

I think in #3 you've made an error in your analysis. As far as I know, const does not imply anything about linkage. I'm not sure how you're coming to the conclusion that the compiler makes the linkage internal. Most compilers will (as an optimization) replace all references to the const variable by the value it's been initialized to, so the symbol may not appear at all in the code.

And even if you didn't, it's clear from #1 that if something with internal linkage is subsequently declared with the extern keyword that it remains with internal linkage. So I don't know why you would expect an error.

And if const implied internal linkage, then #4 should be an error for the same reason #2 is.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • 2
    `const` does imply internal linkage. 7.1.1/6: "A name declared in a namespace scope without a _storage-class-specifier_ has external linkage unless it has internal linkage because of a previous declaration and provided it is not declared `const`. Objects declared `const` and not explicitly declared `extern` have internal linkage." – CB Bailey Aug 21 '10 at 23:24
0

Having both (e) and (f) in the same namespace scope is simply invalid, by §7.1.1/7 "The linkages implied by successive declarations for a given entity shall agree.".

This rule requires a diagnostic.

However, at least Comeau Online does not diagnose the violation.

Cheers & hth.,

EDIT: He he, I looked up DR 426, as mentioned in another answer here, and it seems those who drafted the proposed resolution, making it UB instead of diagnosable, were not aware of §7.1.1/7. I'm not going to comment on the issue or even raise it in comp.std.c++ because I found the standardization work to be far too political and nonsensical (mumbo-jumbo arguments) for me. But either way, the code's not valid.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331