在C ++中,假设我们有这个头文件:
myglobals.h
#ifndef my_globals_h
#define my_globals_h
int monthsInYear = 12;
#endif
并且我们将它包含在多个实现文件中,然后我们将得到编译错误,因为我们最终定义了多次'monthsInYear',每个文件中包含了monthsInYear一次。
精细。因此,如果我们修改标题并创建全局const,就像这样:
const int monthsInYear = 12;
然后我们的编译错误就消失了。根据我的理解和给定here for example,对此的解释是,这里的const关键字将monthsInYear的链接更改为internal,这意味着现在包含标题的每个编译单元现在都有自己的副本具有内部联系的变量,因此我们不再有多个定义。
现在,另一种方法是仅用extern声明变量,即:
extern int monthsInYear;
然后在其中一个包含标题的实现文件中定义它,即:
#include "myglobals.h"
...
int monthsInYear = 12;
...
然后包含它的每个地方都在处理一个带有外部链接的变量。
这很好,但我有点困惑的是,使用const给它内部链接,修复问题,并使用extern给它外部链接,这也解决了问题!这就像说任何联系都会做,只要我们指定它。最重要的是,当我们写下:
int monthsInYear = 12;
是不是外部的联系?这就是为什么添加'const'将链接更改为内部?
在我看来,在这里使用'extern'的原因实际上解决了问题不是因为它给了我们外部链接(我们已经有了),而是因为它允许我们仅仅声明变量而不定义它,我们原本无法做到,因为:
int monthsInYear = 12;
都声明和定义它,并且由于包含头文件有效地将代码粘贴到实现文件中,因此我们最终得到了多个定义。相反,由于extern允许我们仅仅声明它,每次我们包含头时都会得到多个声明,这很好,因为我们允许有多个声明,而不是多个定义。
我的理解是否正确?对不起,如果这是非常明显的,但看起来extern至少做了三件事:
但是我看到的很多来源都没有说清楚,当谈到使用extern来阻止全局变量的“多重定义”错误时,并不清楚关键是将声明与声明分开定义
答案 0 :(得分:2)
对于非const
变量,extern
具有指定变量具有外部链接(这是默认值)的效果,但也转换定义如果没有初始化程序,则进入声明 - 即extern int i;
实际上没有定义i
。 (extern int i = 5;
会,并希望生成编译器警告)。
当您在多个源文件中写入extern int monthsInYear;
时(或者#include
将它们写入它们,这是等效的),它们都没有定义它。 int monthsInYear = 12;
仅定义该源文件中的变量。
答案 1 :(得分:1)
存储类说明符是声明语法的decl-specifier-seq的一部分。它们控制声明引入的名称的两个独立属性:它们的存储持续时间及其链接。
- extern - 静态或线程存储持续时间和外部链接
这就是 cppreference 所说的完全符合您理解的内容。