C++ c++;编译器是否找到外部变量?

C++ c++;编译器是否找到外部变量?,c++,language-lawyer,c++17,C++,Language Lawyer,C++17,我用g++和clang++编写了这个程序。有一点不同: g++打印1,但clang++打印2。 似乎 g++:外部变量在最短范围内定义。 clang++:外部变量在最短的全局范围内定义 C++规范是否有任何说明? main.cpp #include <iostream> static int i; static int *p = &i; int main() { int i; { extern int i; i = 1; *p = 2;

我用g++和clang++编写了这个程序。有一点不同:
g++打印1,但clang++打印2。
似乎
g++:外部变量在最短范围内定义。
clang++:外部变量在最短的全局范围内定义

C++规范是否有任何说明?

main.cpp

#include <iostream>
static int i;
static int *p = &i;

int main() {
  int i;
  {
    extern int i;
    i = 1;
    *p = 2;
    std::cout << i << std::endl;
  }
}

版本:g++:7.4.0/clang++:10.0.0
编译:$(CXX)main.cpp other.cpp-o extern.exe应为标准的相关部分。在目前的草案中,它说:

块作用域中声明的函数名和块作用域
extern
声明中声明的变量名具有链接。如果将这样的声明附加到命名模块,则程序的格式不正确。如果存在具有链接的实体的可见声明,则忽略在最内层封闭命名空间范围外声明的实体,这样,如果两个声明出现在同一声明区域中,则块范围声明将是(可能格式错误的)重新声明,块范围声明声明同一实体并接收前一声明的链接。如果存在多个这样的匹配实体,则程序的格式不正确。否则,如果未找到匹配的实体,则块范围实体将接收外部链接如果在一个翻译单元内,使用内部和外部链接声明了同一实体,则程序的格式不正确。

请注意,下面的示例几乎完全符合您的情况:

static void f();
extern "C" void h();
static int i = 0;               // #1
void g() {
  extern void f();              // internal linkage
  extern void h();              // C language linkage
  int i;                        // #2: i has no linkage
  {
    extern void f();            // internal linkage
    extern int i;               // #3: external linkage, ill-formed
  }
}
因此,该计划应该是格式错误的。下面是示例的说明:

如果第2行没有声明,第3行的声明将与第1行的声明链接。但是,由于具有内部链接的声明是隐藏的,因此#3被赋予了外部链接,这使得程序格式不正确


叮当声给出了正确的结果。即使按照现行标准的规定,程序也不应该是格式错误的。注意强调的措辞:

如果在翻译单元中,使用内部和外部链接声明了相同的实体,则程序的格式不正确

由于以下规则,在
#3
声明的实体和在
#1
声明的实体不是同一实体:

两个相同且在不同范围内声明的名称应表示相同的变量、函数、类型、模板或命名空间,如果

  • 两个名称都有外部链接,或者两个名称都有内部链接,并在同一翻译单元中声明;及
  • [……]
它们不是,一个具有
内部链接
,另一个具有
外部链接
,因此它们不表示相同的实体,因此代码不违反[basic.link#6]。此外,下面的例子[basic.link#6]仍然是关于变量
i
的错误解释

P1787阐明了这个例子。它说:

static void f();
外部“C”void h();
静态整数i=0;//#1.
void gq(){
extern void f();//内部链接
外部void g();/::g,外部链接
extern void h();//C语言链接
int i;/#2:i没有链接
{
extern void f();//内部链接
外部-内部i;//#3:外部-内部链接
}
}
即使第2行的声明隐藏了第1行的声明,第3行的声明也会与第1行的重新声明链接。但是,由于具有和接收内部链接的声明是隐藏的,因此#3被赋予了外部链接,这使得程序格式不正确


这意味着,在您的示例中,声明
extern int i
引入的变量
i
将与声明
static int i
的变量
i
链接。因此,print
2
是正确的行为。

编译器除了将它们标记为具有外部引用的变量外,不会对extern执行任何操作,链接器是尝试解析所有编译的对象文件之间的链接的工具。这是一个极好的(如果奇怪的话)问题!在
MSVC
clang cl
中玩弄你的代码(两者都给出
2
),似乎
extern int i
被两者完全忽略了:即使我没有链接到
other.cpp
文件,程序也会生成并运行。@splaten,由于链接器不需要“解析”对
i
的引用,因此它不会尝试。可以找到相关的旧挂起GCC错误和相应的OpenClang错误。示例中的程序格式错误,因为没有定义外部链接的i。OP的例子不是这样的。@n.“代词m。但这条规则适用于翻译单元:如果在翻译单元内,使用内部和外部链接声明同一实体,则程序的格式不正确。答案仅适用于C++17及更高版本,请参阅的解析。在我看来,GCC在更改之前是正确的。好吧,看起来我在阅读标准的前一版。更新的相关CWG页面[basic.link]和+1。如果实体因链接延迟而不同,如何违反第一条规则D@LanguageLawyer您引用的第一条规则是什么?如果在翻译单元中,同一实体同时声明了内部和外部链接,则程序的格式不正确。@LanguageLawyer我没有说代码违反了该规则。因为它们不是相同的实体,类似于。也许你的意思是我不应该说
违反
,而应该说
不符合规则
static void f();
extern "C" void h();
static int i = 0;               // #1
void g() {
  extern void f();              // internal linkage
  extern void h();              // C language linkage
  int i;                        // #2: i has no linkage
  {
    extern void f();            // internal linkage
    extern int i;               // #3: external linkage, ill-formed
  }
}