各种const / static变量的链接

时间:2010-08-21 20:18:23

标签: c++ static extern linkage

我对以下变量的链接有几个问题。通过C ++ 03的7.1.1 / 7和编译器(Comeau,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,然后是static

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

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

  3. 首先const,然后是extern

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

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

  4. 首先extern,然后是const

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

    现在,(g)意味着外部联系,因为我们明确宣布了extern。 (h)也暗示外部联系,因为(g)明确宣布外部联系。


  5. 我已经通过以下模板实验性地发现了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,也未显式声明   以前宣布有外部联系;
    •   

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

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

    2. 第二种解释解释了“声明”的出现以引用同一声明。这样,就意味着被声明为const,而不是extern const 。我们注意到(e)被声明为const而非extern const,因此我们提供pi1内部链接。

    3. 现在什么解释是正确的?我无法从这个措辞中确定,但编译器似乎是第二种解释。特别是,如果我们采用第一种解释,那么3.5/3的最后引用部分将是多余的,因为没有有效的方案,其中将声明名称const并且之前使用外部链接声明但没有明确的extern

3 个答案:

答案 0 :(得分:4)

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或[... blah ...]的对象的名称。我认为这是因为它是在(e)点宣布的。当然,它并没有在任何地方声明,但同样的方式a是我们在考虑static声明时声明extern int a;声明的对象的名称,即使它未被声明static无处不在。对我而言,这意味着声明(f)并不意味着与声明(e)有不同的联系。

答案 1 :(得分:0)

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

即使你没有,从#1中可以清楚地看出,如果随后用extern关键字声明内部链接的东西,它仍保留内部链接。所以我不知道你为什么会出现错误。

如果const暗示内部联系,那么#4应该是错误,出于同样的原因#2是。

答案 2 :(得分:0)

同一命名空间范围内的(e)和(f)都是无效的,§7.1.1/ 7“给定实体的连续声明所暗示的联系应该同意。”。

此规则需要诊断。

但是,至少Comeau Online不会诊断违规行为。

干杯&amp;第h。,

编辑:他,我抬头DR 426,正如另一个答案中提到的那样,似乎那些起草提议的决议,使其成为UB而不是可诊断的,不是意识到§7.1.1/ 7。我不打算对这个问题发表评论,甚至不会在comp.std.c ++中提出它,因为我发现标准化工作对我来说太政治化和荒谬(mumbo-jumbo论证)。但无论哪种方式,代码都无效。