const和全球

时间:2012-01-27 11:14:29

标签: c++ global-variables const extern

此代码将在c ++中生成错误

// Foo.cpp
const int Foo = 99;

// Main.cpp
extern const int Foo;
int main()
{
    cout << Foo << endl;
    return 0;
}    

许多人给出的原因是全局const有内部范围,它是默认的静态。

对此的解决方案是: -

    //Foo.h
    extern const int Foo; 

    // Foo.cpp
    #include "Foo.h"
    const int Foo = 99; 

    // Main.cpp
    #include "Foo.h"
    int main()
    {
       cout << Foo << endl;
    }

我以前认为extern用于告诉编译器,已经在其他文件中的某处将分配的内存分配给了。 在上面的代码中应用相同的逻辑可以解释这里发生的事情,或者extern在c ++中有不同的含义 enter link description here
还要考虑这个页面,这会破坏我的所有直觉......

2 个答案:

答案 0 :(得分:7)

如果我们必须只声明一个全局常量(不是static)怎么办? extern如何帮助您做到这一点?

使用const限定符声明的extern对象具有外部链接 因此,如果您想在多个翻译单元中使用const,请为其添加extern限定符。

默认情况下,全局变量具有外部链接,为什么const全局默认具有内部链接?

参考:
C ++ 03标准附录C兼容性C.1.2第3条:基本概念

  

更改:显式声明为const且未显式声明为extern的文件范围名称具有内部链接,而在C中则具有外部链接

     

基本原理:因为const对象可以在C ++中用作编译时值,所以这个特性促使程序员为每个const提供显式的初始化值。此功能允许用户将const对象放在许多编译单元中包含的头文件中。


遵循一条简单的规则避免混淆:

默认情况下,Linkage对于非const符号是外部的,对于const符号是静态的(内部的)。

答案 1 :(得分:3)

快速提醒,以便我们所说的很清楚:

int const a;            //  illegal
int const a = 42;       //  definition, internal linkage
extern int const a;         //  declaration, external linkage
extern int const a = 42;    //  definition , external linkage

请注意,如果没有const,上面的前两个声明都是 外部联系的定义。这不是正交的,而且 不是很直观,但这是现行规则所说的。

给出const外部链接的问题是可以存在 只有一个具有外部链接的对象的定义,并且只有一个 例外,只有定义可以有一个初始化程序。这意味着 对于具有外部链接的const,实际值(如果是 const用于常量表达式)只能在一个中可见 翻译单位。这可能是给予const的动机 内部链接默认情况下。

当然,这至少会导致模板无法解决问题 理论上;如果是,则以下标头具有未定义的行为 包括在多个翻译单元中:

#include <std::vector>

int const fixedValue = 42;
inline void insertFixedValue( std::vector<int>& dest )
{
    dest.push_back( fixedValue );
}

标准规定,不仅内联功能和模板必须具备 一个相同的标记序列,但所有符号必须绑定 每个翻译单元中的同一个对象,或者有违反 一个定义规则。由于fixedValue没有外部因素 链接,每个翻译单元都有一个唯一的实例。 (有 一个例外如果符号引用const对象那么 rvalue转换的直接左值。以来 然而,std::vector<int>::push_back通过引用来论证其论点, rvalue转换没有立即左值,我们得到了未定义 行为)。

当然,任何人都有模板:

template <int& r> ...

无法使用fixedValue实例化它。

内部联系的原因当然是历史性的。今天, 编译器必须能够支持以下内容:

struct X
{
    static int const a = 42;    //  declaration!!!, external linkage
};

以及函数的各种重复定义。这将是 相对简单的扩展规则允许初始化器 在类中声明命名空间范围内的变量,给出 类似的东西:

int const a;                //  illegal
int const a = 42;           //  definition, external linkage
extern int const a;         //  declaration, external linkage
extern int const a = 42;    //  declaration, external linkage

这将恢复正交性(即使它需要额外输入)。它 也会破坏几乎所有现有的代码。

另一种选择是处理const变量定义 就像今天处理的功能模板一样:你可以有多个 定义,但它们必须完全相同。这可能会避免 大多数(如果不是全部)代码破坏。