块作用域外部声明

问题描述 投票:0回答:4

C++11标准给出了下面的代码片段(我删除了不相关的代码)并表示名称

i
具有外部链接。 (第 3.5.6 条)

static int i = 0; // #1
void g() {
    extern int i; // #3 external linkage
}

他们为什么要这样做?我是不是误会了什么?这两个

i
在vs2012中指的是同一个对象。当我在其他地方使用
i
时,我遇到了未解决的外部错误。我不知道vs2012是否支持这个功能。

编辑: 我认为 VS2012 做的是正确的事情。 #3 中的

i
只需要引用具有链接的
i
即可。如果编译器找不到,则应在其他翻译单元中定义
i
。所以上面代码片段中的两个
i
应该指的是同一个对象。

标准引用:

如果存在具有链接的实体的可见声明 相同的名称和类型,忽略最内层之外声明的实体 封闭命名空间范围,块范围声明声明 同一实体并接收先前声明的链接。如果 没有找到匹配的实体,块作用域实体接收外部 联动。

但是为什么人们需要这个功能?

c++ c++11
4个回答
7
投票

#3
只是一个声明;它指出程序中某处存在一个名为
i
的变量,具有外部链接,但没有定义该变量。该声明允许您在
#1
的范围内使用它,而不是
g
中的静态变量。

您还需要在包含

g
的命名空间中定义它。在这种情况下,它必须位于不同的翻译单元中,这样它就不会与同名的静态变量冲突。

需要明确的是,这里有两个不同的变量,称为

i
,如示例后面的段落中所述。
#1
在这里定义;
#3
只是声明,需要单独定义。


2
投票
static int i = 0; // #1
void g() {
    extern int i; // #3 external linkage
}

第一个

static
i
是一个声明,仅在当前源文件中可见。

extern int i; 

告诉编译器我的意思不是这个

static i
,而是在其他地方定义的另一个
i
。如果您尚未在其他地方(在另一个翻译单元中)定义它,您将获得未定义的引用。

这不会破坏 ODR,因为这个(

static
i
是静态的(仅在本单元中可见)。


1
投票
extern int i;

承诺编译器我会给你一个

int i

static int i=0;
不是承诺的变量,您必须在该
int i
变量声明可见的其他地方声明
extern

换句话说,

extern int i;
static int i=0;
是两个不相关的变量。


0
投票

程序的行为在最新的 C++ 标准 (c++23) 中发生了变化。

extern int i;
现在在 C++23 中具有 内部链接。特别是,给定的程序在 C++17 到 C++20 中是“格式错误”的,但在 C++23 中它是“格式正确的”,如下所述。在 C++11/14 中,extern int i; 具有外部链接,并且程序在 C++11/14 中格式良好。 C++23

extern int i;

现在具有按照

basic.link

:

 的内部链接
[示例1:

static void f(); extern "C" void h(); static int i = 0; // #1 void q() { extern void f(); // internal linkage extern void g(); // ​::​g, external linkage extern void h(); // C language linkage int i; // #2: i has no linkage { extern void f(); // internal linkage extern int i; // #3: internal linkage } }

即使第 #2 行的声明隐藏了第 #1 行的声明,第 #3 行的声明仍然重新声明 #1 并接收内部链接。
—结束示例]

© www.soinside.com 2019 - 2024. All rights reserved.