此代码将在c++中产生错误
// Foo.cpp
const int Foo = 99;
// Main.cpp
extern const int Foo;
int main()
{
cout << Foo << endl;
return 0;
}
许多人给出的原因是全局常量具有内部作用域,并且它是默认的静态常量。
解决方案是:-
//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++中有不同的含义
在此处输入链接描述
再想想这一页,它破坏了我所有的直觉。。
如果我们必须只声明一个全局常量(而不是static
)怎么办?extern
如何帮助做到这一点
用extern
限定符声明的const
对象具有外部链接
因此,如果您想在多个翻译单元中使用const
,请添加一个extern
限定符
虽然全局变量默认具有外部链接,但为什么常量全局默认具有内部链接
参考:
C++03标准附录C兼容性C.1.2第3条:基本概念
更改:明确声明为const而未明确声明为extern的文件作用域的名称具有内部链接,而在C中则具有外部链接
理由:由于const对象可以用作C++中的编译时值,因此此功能敦促程序员为每个const提供显式初始值设定项值。此功能允许用户将const对象放入包含在许多编译单元中的头文件中。
通过遵循一个简单的规则来避免混淆:
默认情况下,对于非常量符号,Linkage是外部的,对于常量符号,它是静态的(内部的)。
一个快速提醒,让我们清楚地了解我们在谈论什么:
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
的动机默认情况下为内部链接。
当然,这至少会导致模板问题层出不穷理论上;以下标头具有未定义的行为(如果是)包括在多个翻译单元中:
#include <std::vector>
int const fixedValue = 42;
inline void insertFixedValue( std::vector<int>& dest )
{
dest.push_back( fixedValue );
}
该标准规定,内联函数和模板不仅必须具有相同的令牌序列,但所有符号都必须绑定到每个翻译单元中的同一对象,或者违反一个定义规则。由于fixedValue
没有外部链接,在每个翻译单元中都有一个唯一的实例。(有异常如果符号引用const
对象并且存在立即从左值到右值的转换。自从CCD_,没有立即的左值到右值的转换,我们得到了未定义行为。)
当然,任何有模板的人:
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
变量定义正如今天处理的函数模板一样:您可以有多个定义,但它们必须完全相同。这可能会避免大部分(如果不是全部的话)代码破坏。