C ++ 컴파일러는 extern 변수를 어떻게 찾습니까? 정의 된 것 같습니다 . clang

이 프로그램을 g ++ 및 clang ++로 컴파일합니다. 차이점은 다음과 같습니다.
g ++는 1을 인쇄하지만 clang ++는 2를 인쇄합니다.
g ++ : extern varible은 가장 짧은 범위에서 정의 된
것 같습니다
.
clang ++ : extern varible은 가장 짧은 전역 범위에서 정의됩니다.

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

other.cpp

int i;

버전 : g ++ : 7.4.0 / clang ++ : 10.0.0
컴파일 : $ (CXX) main.cpp other.cpp -o extern.exe



답변

[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
  }
}

따라서 프로그램이 잘못 구성되어야합니다. 설명은 예제 아래에 있습니다.

2 번 줄에 선언이 없으면 3 번 줄의 선언이 1 번 줄의 선언과 연결됩니다. 그러나 내부 연계가있는 선언은 숨겨져 있기 때문에 # 3에 외부 연계가 제공되므로 프로그램이 잘못 작성됩니다.