在C++中的给定相同范围内声明相同的变量名称

Jay*_*esh 3 c++ variables storage one-definition-rule

我试图理解C++中的存储类说明符.我有两个案子.

这里,在给定的相同范围内,声明相同的变量名称.

情况1:

#include <iostream>

static int i; 
extern int i; 

int main() {
    std::cout<<i<<std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

0
Run Code Online (Sandbox Code Playgroud)

案例2:

#include <iostream>

extern int i; 
static int i; 

int main() {
    std::cout<<i<<std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

得到错误:

prog.cpp:4:12: error: 'i' was declared 'extern' and later 'static' [-fpermissive]
 static int i; 
            ^
prog.cpp:3:12: note: previous declaration of 'i'
 extern int i;
Run Code Online (Sandbox Code Playgroud)

为什么第一种情况正常,而第二种情况却出错?

Seb*_*edl 13

extern有点奇怪,因为标有它的声明会查找同一实体的先前声明,如果找到,则使用之前的链接.只有当它找不到时才会声明具有外部链接的新实体.

static另一方面,无条件地宣布其实体具有内部联系.

这意味着此代码只是i通过内部链接声明和定义.第二个声明找到第一个并重新使用它的链接.

static int i;
extern int i;
Run Code Online (Sandbox Code Playgroud)

而此代码声明变量具有外部链接,然后声明并定义它以具有内部链接,这是一个错误.

extern int i;
static int i;
Run Code Online (Sandbox Code Playgroud)

这种行为的原因很难跟踪,但最有可能回到C标准前的日子.

在C++中,此行为由[basic.link]指定,在最新的N4687草案中为6.5/6:

在块作用域中声明的函数的名称和由块作用域extern声明声明的变量的名称具有链接.如果存在具有相同名称和类型的链接的实体的可见声明,忽略在最内部封闭命名空间范围之外声明的实体,则块范围声明声明该实体并接收先前声明的链接.如果存在多个这样的匹配实体,则该程序是不正确的.否则,如果未找到匹配的实体,则块范围实体接收外部链接.