此代码编译良好:
extern int i = 10;
void test()
{
std::cout << "Hi" << i << std::endl;
}
虽然此代码出错:
void test()
{
extern int i = 10;
std::cout << "Hi" << i << std::endl;
}
错误:'我'同时拥有'extern'和初始化程序
我在C++ Primer中看到了这个:
包含显式初始值设定项的任何声明都是一个定义。 我们可以在定义为extern的变量上提供初始化器,但是 这样做会覆盖extern。具有初始化器的extern是a 定义。 在内部的extern上提供初始化程序是错误的 功能
有人可以提供一个解释,说明如果在函数中本地完成这是一个错误,而在全局范围内允许这样做吗?
答案 0 :(得分:18)
在函数内定义外部变量的原因没有意义如下:
当您声明符号extern时,您告诉编译器将此值的所有此类实例链接到同一符号。任何extern int i出现;在你的程序中将链接到外部定义的i。看看这个例子:
#include <iostream>
using namespace std;
extern int i;
int i = 10;
void test()
{
std::cout << "Hi" << i << std::endl;
}
int main()
{
extern int i;
i++;
test();
}
此示例应输出hi11。 HOwever,如果我们删除主内部的extern,它将输出10.这是因为没有extern,我没有链接到全局i,但创建它自己的本地副本i。
如果我们允许任何函数“定义”i,那么在函数内定义extern i的原因是没有意义的。哪个功能先运行?什么时候定义?
假设以下示例有效,输出是什么???
#include <iostream>
using namespace std;
extern int i;
int i = 10;
void test()
{
std::cout << "Hi" << i << std::endl;
}
void test2() {
extern int i = 1000;
std::cout<< "HI" << i << std::endl;
}
void test3() {
extern int i;
i = 1000;
std::cout<< "HI" << i << std::endl;
}
int main()
{
extern int i;
i++;
test();
i = 0;
test2();
}
test2的输出应该是0还是1000?另外看看我的test3,这里我们简洁地说,将我的i链接到外部定义的i,并将其值分配为1000.这与尝试“初始化”值非常不同。
简而言之,外部变量实际上只作为全局变量有意义,并且应该在全局范围内定义。在您的示例中,第一个版本不会为我编译。我发现这很有趣。可能值得查看标准文档,看看它是否被简明地定义,或者您的编译器是否可能以旨在添加额外保护的方式处理它...
答案 1 :(得分:7)
通过在声明中添加初始化器,它将成为全局变量的定义。它相当于没有extern
的相同定义,这就是当你的书“覆盖外部”时你的书的含义。
虽然可以在函数内声明全局变量(使用extern
),但是只能在命名空间范围内定义它们。这就是为什么第二个片段是错误的。
如果你想知道为什么C的设计者(这些规则来自C ++)选择允许声明而不是这里的定义,那么我恐怕我不太清楚地知道语言的历史。< / p>
答案 2 :(得分:4)
首先,您应该熟悉链接的概念和外部链接的含义:
当一个名称可能表示同一个对象时,该名称被认为具有链接, 引用,函数,类型,模板,命名空间或值作为名称 由另一个范围内的声明引入:
当名称具有外部链接时,它表示的实体可以是 来自其他翻译单位范围的名称或来自 同一翻译单位的其他范围。
- 3.5.6.2 n3242
static
的功能与extern
不同,extern
只是一个请求,static
是一个命令。
在块作用域中声明的函数的名称和a的名称 由块作用域extern声明声明的变量具有链接。
- 如果存在具有相同名称和类型的链接的实体的可见声明,忽略在最内部封闭命名空间范围之外声明的实体,则块范围声明声明该实体并接收先前声明的链接。
- 如果有多个此类匹配实体,则该程序格式不正确。
- 否则,如果未找到匹配的实体,则块范围实体将接收外部链接。
- 3.5.6.6 n3242
因此,在块范围内,建议执行以下步骤:
extern int i;//declare it,request the linkage according to 3.5.6.6 above
i = 10;//modify it when has link to a defination
对于全局extern声明可能是转换形式
extern int i =10;
到
extern int i;//include in .hpp is recommended
int i =10;//global or namespace variable defination
答案 3 :(得分:0)
最简单的说法:
extern
关键字的目的是声明一个对象而不定义它。通过定义它,您基本上可以告诉编译器&#34;不要分配值但是分配值&#34;。这没有意义 - 在函数外部的或内部永远不应该这样做。大多数编译器要么警告你,要么继续进行,否则他们根本不会编译并给出错误。
虽然详细解释 extern
的内容超出了此问题的范围,但您可能会发现阅读答案很有用this question。
答案 4 :(得分:0)
extern
变量:
en.cppreference.com/w/cpp/language/initialization#Non-local_variables
如果在功能块中声明static
而不是extern
,它仍然会有静态存储持续时间,但它的&#39; 链接将本地与外部相对应。因此,当执行首次遍历函数中的该行时,它将被初始化:
en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables
因此可以在功能块中初始化static
变量,但不能在那里初始化extern
变量。