C++ 编译器如何找到一个 extern 变量?

edd*_*kuo 16 c++ language-lawyer c++17

我用 g++ 和 clang++ 编译这个程序。有一个区别:
g++ 打印 1,但 clang++ 打印 2。
似乎
g++: extern 变量定义在最短范围内。
clang++:extern 变量定义在最短的全局范围内。

C++ 规范对此有任何规范吗?

主程序

#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;
  }
}

Run Code Online (Sandbox Code Playgroud)

其他.cpp

int i;
Run Code Online (Sandbox Code Playgroud)

版本:g++:7.4.0/clang++:10.0.0
编译:$(CXX) main.cpp other.cpp -o extern.exe

Dan*_*ica 12

[basic.link/7]应该是标准的相关部分。在目前的草案中,它说:

块作用域中声明的函数名和块作用域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
  }
}
Run Code Online (Sandbox Code Playgroud)

所以,程序应该是格式错误的。解释在示例下面:

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

  • @n.'代词'm。但该规则适用于翻译单元:_如果在翻译单元内,使用内部和外部链接声明同一实体,则程序格式错误。_。 (3认同)
  • 该答案仅适用于 C++17 及更高版本,请参阅 [CWG 问题 426](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#426) 的解决方案。在我看来,GCC 在这次改变之前是正确的。 (2认同)