extern 在命名空间中如何工作?
How does extern work in namespaces?
我正在 运行创建一个类似于我发现的 here 的简单程序。它旨在减少在多个文件中包含常量时的代码膨胀。它通过在命名空间中使用 const 全局变量及其各自的 extern
前向声明来实现。
globals.h
#ifndef GLOBALS_H_
#define GLOBALS_H_
namespace Constants
{
// forward declarations only
extern const double pi;
extern const double avogadro;
extern const double my_gravity;
}
#endif
globals.cpp
namespace Constants
{
// actual global variables
extern const double pi(3.14159);
extern const double avogadro(6.0221413e23);
extern const double my_gravity(9.2); // m/s^2 -- gravity is light on this planet
}
source.cpp
#include <iostream>
#include <limits>
#include "globals.h"
int main()
{
double value_of_pi = Constants::pi;
std::cout << value_of_pi;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin.get();
return 0;
}
我假设 Constants::pi 获取 globals.cpp 常量命名空间中包含的值 pi,并且能够这样做是因为它可以从包含的 globals.h 访问命名空间本身.我不明白的是为什么 globals.cpp 中的 const global definitions/initializations 需要 extern
关键字?我尝试删除 globals.cpp 中的 extern
关键字,认为不需要它,但没有它们我的程序不会 运行。我以为 extern
只用于前向声明?为什么 const global definitions/initializations 需要它们?与它们定义的命名空间有关吗?
It's meant to reduce code bloat when including constants in multiple files
我建议除非真的有必要,否则不要专注于这种优化,而是选择最简单的设计:直接在头文件中定义这些常量,并从所有翻译单元(.cpp)中包含该头文件文件”)需要访问这些常量。由于这些对象是 const
,它们将具有内部链接,并且链接器不会因为违反单一定义规则而对您尖叫。
I tried removing the extern keywords in globals.cpp thinking that it wasn't needed, but my program won't run without them
这是因为具有静态存储持续时间的名称空间范围 const
对象(如您的 pi
变量)具有 内部链接 除非您将它们明确定义为 extern
.
I thought extern was only used for forward declarations?
extern
用于声明在另一个翻译单元(.cpp 文件)中定义的变量。如果对象是 const
,定义它的翻译单元需要将其显式标记为 extern
,以便它具有外部链接并从其他翻译单元可见(如果该对象不是 const
)。
Has it something to do with the namespace they are defined in?
不,这是所有具有静态存储持续时间的名称空间级 const
对象的规则,它在 C++ 标准的段落 [basic.link]/3 中指定:
A name having namespace scope (3.3.6) has internal linkage if it is the name of
(3.1) [...] — a variable, function or function template that is explicitly
declared static; or,
(3.2) — a variable of non-volatile const-qualified type that is neither explicitly declared extern nor previously declared to have external linkage; or
(3.3) — a data member of an anonymous union.
我正在 运行创建一个类似于我发现的 here 的简单程序。它旨在减少在多个文件中包含常量时的代码膨胀。它通过在命名空间中使用 const 全局变量及其各自的 extern
前向声明来实现。
globals.h
#ifndef GLOBALS_H_
#define GLOBALS_H_
namespace Constants
{
// forward declarations only
extern const double pi;
extern const double avogadro;
extern const double my_gravity;
}
#endif
globals.cpp
namespace Constants
{
// actual global variables
extern const double pi(3.14159);
extern const double avogadro(6.0221413e23);
extern const double my_gravity(9.2); // m/s^2 -- gravity is light on this planet
}
source.cpp
#include <iostream>
#include <limits>
#include "globals.h"
int main()
{
double value_of_pi = Constants::pi;
std::cout << value_of_pi;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin.get();
return 0;
}
我假设 Constants::pi 获取 globals.cpp 常量命名空间中包含的值 pi,并且能够这样做是因为它可以从包含的 globals.h 访问命名空间本身.我不明白的是为什么 globals.cpp 中的 const global definitions/initializations 需要 extern
关键字?我尝试删除 globals.cpp 中的 extern
关键字,认为不需要它,但没有它们我的程序不会 运行。我以为 extern
只用于前向声明?为什么 const global definitions/initializations 需要它们?与它们定义的命名空间有关吗?
It's meant to reduce code bloat when including constants in multiple files
我建议除非真的有必要,否则不要专注于这种优化,而是选择最简单的设计:直接在头文件中定义这些常量,并从所有翻译单元(.cpp)中包含该头文件文件”)需要访问这些常量。由于这些对象是 const
,它们将具有内部链接,并且链接器不会因为违反单一定义规则而对您尖叫。
I tried removing the extern keywords in globals.cpp thinking that it wasn't needed, but my program won't run without them
这是因为具有静态存储持续时间的名称空间范围 const
对象(如您的 pi
变量)具有 内部链接 除非您将它们明确定义为 extern
.
I thought extern was only used for forward declarations?
extern
用于声明在另一个翻译单元(.cpp 文件)中定义的变量。如果对象是 const
,定义它的翻译单元需要将其显式标记为 extern
,以便它具有外部链接并从其他翻译单元可见(如果该对象不是 const
)。
Has it something to do with the namespace they are defined in?
不,这是所有具有静态存储持续时间的名称空间级 const
对象的规则,它在 C++ 标准的段落 [basic.link]/3 中指定:
A name having namespace scope (3.3.6) has internal linkage if it is the name of
(3.1) [...] — a variable, function or function template that is explicitly declared static; or,
(3.2) — a variable of non-volatile const-qualified type that is neither explicitly declared extern nor previously declared to have external linkage; or
(3.3) — a data member of an anonymous union.