代码之家  ›  专栏  ›  技术社区  ›  Johannes Schaub - litb

各种常量/静态变量的链接

  •  6
  • Johannes Schaub - litb  · 技术社区  · 15 年前

    我有几个关于以下变量的链接的问题。通过C++ 03的7.1.1/7的例子和编译器(COMMO,Clang和GCC)的实验,我得出以下的链接类型:

    1. 弗斯特 static 然后 extern

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

      我很清楚,根据第3.5节:(a)意味着内部联系。并且(b)也意味着内部链接,因为名称“a”被声明为静态的(通过(a))。

    2. 弗斯特 外部的 然后 静止的

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

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

    3. 弗斯特 const 然后 外部的

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

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

    4. 弗斯特 外部的 然后 康斯特

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

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


    我已经用下面的模板实验了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)是

    • 一种对象或引用,它被显式声明为常量,而不是显式声明为extern或 先前宣布具有外部联系;

    如果我们看点 (f) 然后这两种解释得出了不同的结论,如下所示

    1. 第一个解释指出 pi1 被宣布 康斯特 但也被宣布 外部的 . 因此,变量 外部的 连锁。

    2. 第二种解释解释了“已声明”指同一声明的两种情况。这样,就意味着 被宣布 康斯特 ,但不是 extern const . 我们注意到 (e) 被宣布 康斯特 而不是 外部常数 因此,我们给予 PI1 内部联动装置。

    现在什么解释是正确的?我不能从那个措词来判断,但编译器似乎是用第二种方式来解释这个问题。特别是,如果我们采用第一种解释,那么最后引用的部分 3.5/3 这将是多余的,因为在没有有效方案中声明名称 康斯特 以前用外部链接声明,但没有显式 外部的 .

    3 回复  |  直到 15 年前
        1
  •  4
  •   CB Bailey    15 年前
    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 显式声明的对象的名称 康斯特 但都没有明确声明 外部的 也不…瞎说……我认为这是因为它是在第(e)点宣布的。当然,不是所有地方都这么说的,但方式是一样的 a 是否声明了对象的名称 static 当我们考虑 extern int a; 声明,即使没有声明 静止的 到处都是。对我来说,这意味着声明(f)并不意味着与声明(e)有不同的联系。

        2
  •  0
  •   Omnifarious    15 年前

    我认为在3中,你在分析中犯了一个错误。据我所知, const 并不意味着任何联系。我不确定您是如何得出这样的结论的:编译器使链接成为内部的。大多数编译器(作为一种优化)都会将对const变量的所有引用替换为它初始化为的值,因此符号可能根本不会出现在代码中。

    即使你没有,从1可以清楚地看出,如果随后用 extern 关键字,它与内部链接一起保留。所以我不知道你为什么会有错误。

    如果 康斯特 隐含的内部链接,那么4应该是一个错误,原因与2相同。

        3
  •  0
  •   Cheers and hth. - Alf    15 年前

    根据第7.1.1/7节的规定,将(e)和(f)同时放在同一名称空间范围内是完全无效的,“对给定实体的连续声明所暗示的联系应一致”。

    此规则需要诊断。

    但是,至少comeau在线并没有诊断出违规行为。

    干杯!

    编辑 他,我抬头看了看。 DR 426 如本文另一个答案所述,似乎起草拟议决议的人不知道第7.1.1/7节,因为该决议是UB而不是可诊断的。我不会对这个问题发表评论,甚至不会在comp.std.c++中提出来,因为我发现标准化工作对我来说太政治化和毫无意义(冗长的争论)。但是无论如何,代码都是无效的。