各种const/static变量的链接

发布于 2024-09-15 01:38:48 字数 2222 浏览 8 评论 0原文

我对以下变量的联系有一些疑问。通过 C++03 7.1.1/7 的示例并尝试编译器(Comeau、Clang 和 GCC),我得出以下链接类型:

  1. 首先 static,然后 外部

    static int a; //(一)
    外部整数a; // (b) 有效,'a' 仍然是内部的
    

    根据第 3.5 节,我很清楚:(a) 暗示内部链接。并且 (b) 还暗示内部链接,因为名称“a”被声明为静态(由 (a) 声明)。

  2. 首先是extern,然后是static

    extern int b; //(三)
    静态 int b; // (d) 无效!
    

    首先,(c) 意味着外部链接。但 (d) 暗示了内部链接,因为名称“b”被 (d) 声明为静态。根据 7.1.1/7,这是无效的,因为隐含的链接不一致。

  3. 首先是const,然后是extern

    const double pi1 = 3.14; //(e)
    外部常量双 pi1; // (f) 有效且“pi1”是内部的
    

    首先,(e) 意味着内部链接,因为它是 const,并且既没有声明显式 extern,也没有先前隐含的外部链接。 (f) 应该暗示 extern 链接并且是一个错误,因为它显式声明了名称 extern,但编译器将其保留在内部! 为什么会这样? 这是我的问题。

  4. 首先是 extern,然后是 const

    extern const double pi2; //(克)
    常量双 pi2 = 3.14; // (h) 有效且“pi2”是外部的
    

    现在,(g) 意味着外部链接,因为我们显式声明了 extern。并且 (h) 还意味着外部链接,因为 (g) 显式声明了 extern。


我已经通过以下模板通过实验找到了 3 和 4 的链接(第二个参数需要具有外部链接)

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

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

摘要:Charles Bailey 结果非常富有成效,并表明 3.5/3 有两种可能的解释,其中重要的要点如下

具有命名空间范围 (3.3.5) 的名称如果是以下名称,则具有内部链接

  • 显式声明为 const 且既未显式声明为 extern 也未显式声明为 const 的对象或引用 先前声明具有外部链接;

如果我们看一下(f)点,那么两种解释会得出不同的结论,如下所示

  1. 第一种解释指出pi1被声明为const 但也被声明为 extern。因此,该变量具有外部链接。

  2. 第二种解释将两次出现的“declared”解释为指同一个声明。这样,就意味着它被声明为 const,而不是 extern const。我们注意到 (e) 被声明为 const 而不是 extern const,因此我们给出了 pi1 内部链接。

现在什么解释是正确的?我无法从该措辞中确定,但编译器似乎以第二种方式解释这一点。特别是,如果我们采用第一种解释,那么 3.5/3 最后引用的部分将是多余的,因为不存在将名称声明为 const 的有效场景。 code> 和先前使用外部链接声明但没有显式 extern 的情况。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

带上头具痛哭 2024-09-22 01:38:48
const double pi1 = 3.14; // (e)
extern const double pi1; // (f) valid and 'pi1' is internal

我的解释如下。在考虑名称的链接时,我们会考虑先前的声明以及此时在解析中解释的声明。这就是为什么static int a; extern int a; 可以,但是 extern int b; static int b; 不是。

在遇到第一个声明时,我们注意到 pi1 被显式声明为 const,但既没有显式声明 extern,也没有先前声明为具有外部链接。这与 3.5/2 的选项之一匹配,因此 pi1 具有内部链接。

遇到第二个声明时,我们询问的是 pi1 显式声明 const 但既不显式声明 extern 也不显式声明 [...等等……]。我认为这是因为它是在(e)点如此声明的。当然,它并不是在任何地方都以这种方式声明的,但就像我们在考虑 extern int a; 时,a 是声明 static 的对象的名称一样。 声明,即使它没有在任何地方声明为 static 。对我来说,这意味着声明 (f) 并不意味着与声明 (e) 不同的链接。

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

贪恋 2024-09-22 01:38:48

我认为在#3 中你的分析犯了错误。据我所知, const 并不暗示任何有关链接的内容。我不确定您如何得出编译器将链接设为内部的结论。大多数编译器将(作为优化)将所有对 const 变量的引用替换为其初始化的值,因此该符号可能根本不会出现在代码中。

即使您没有这样做,从 #1 中也可以清楚地看出,如果随后使用 extern 关键字声明具有内部链接的内容,那么它仍然具有内部链接。所以我不知道为什么你会期待一个错误。

如果 const 暗示内部链接,那么 #4 应该是一个错误,原因与 #2 相同。

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.

所谓喜欢 2024-09-22 01:38:48

根据第 7.1.1/7 节“给定实体的连续声明所隐含的链接应一致”,将 (e) 和 (f) 放在同一名称空间范围中是完全无效的。

该规则需要诊断。

然而,至少 Comeau Online 没有诊断出违规行为。

干杯& hth.,

编辑:呵呵,我查了一下DR 426,正如另一个答案中提到的,似乎那些起草拟议决议的人,使其成为 UB 而不是可诊断的,并不知道 §7.1.1/7。我不会评论这个问题,甚至不会在 comp.std.c++ 中提出它,因为我发现标准化工作对我来说太过政治化和无意义(胡言乱语)。但无论哪种方式,代码都是无效的。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文