各种const/static变量的链接

Joh*_*itb 6 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
    
    Run Code Online (Sandbox Code Playgroud)

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

  2. 首先extern,然后static

    extern int b; // (c)
    static int b; // (d) invalid!
    
    Run Code Online (Sandbox Code Playgroud)

    首先,(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
    
    Run Code Online (Sandbox Code Playgroud)

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

  4. 首先extern,然后const

    extern const double pi2; // (g)
    const double pi2 = 3.14; // (h) valid and 'pi2' is external
    
    Run Code Online (Sandbox Code Playgroud)

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


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

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

ensure<const double, pi1> e1; // failed
ensure<const double, pi2> e2; // succeeded
Run Code Online (Sandbox Code Playgroud)

摘要:查尔斯贝利的讨论结果非常富有成果,并表明有两种可能的解释3.5/3,其中重要的要点是

具有命名空间作用域(3.3.5)的名称具有内部链接(如果它的名称)

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

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

  1. 第一个解释说明了pi1已宣布const但也已宣布extern.因此变量具有外部联系.

  2. 第二种解释解释了"声明"的出现以引用同一声明.通过这种方式,它意味着它被声明const,但不是extern const.我们注意到这(e)是宣布const而不是extern const,因此我们提供pi1内部联系.

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

CB *_*ley 4

const double pi1 = 3.14; // (e)
extern const double pi1; // (f) valid and 'pi1' is internal
Run Code Online (Sandbox Code Playgroud)

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

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

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