사용

2014-04-29 8 views
11

연타, GCC 및 VS2013 모든 main()에서 w의 재정에 대해 불평하지만, 나는 이것을 허용하지 표준 아무것도 찾을 수 없습니다.사용

namespace N { 
    extern int j; 
    int j; 
} 

int main() 
{ 
    extern int w; 
    int w; 
} 

이 단락은 블록 범위에 extern 선언의 사용에 대해 뭔가 말을하지만, 오류 메시지가 정당화하지 않는 것 :

§3.3.1/4

을 단일 선언 영역에서 일련의 선언이 주어진 경우 ...

[참고 : 이러한 제한은 이름이 도입 된 선언적 영역에 적용됩니다. 선언이 발생하는 영역 과 반드시 ​​동일하지는 않습니다. 특히, 는 정교 타입 - 지정자 (7.1.6.3)과 친구 선언 (11.3) 를 클로징 네임 스페이스에 (아마도 보이지 않는)의 이름을 소개 할 수있다; 이러한 제한 사항은 해당 지역에 적용됩니다. 로컬 통근 선언 (3.5) 선언적 영역 선언 표시하며 바깥 쪽 공간로 (가능하지 표시)를 도입 이름에 이름을 초래할 수있다; 이 제한 사항은 두 지역 모두 에 적용됩니다. -end 노트]

§3.3.2/10

[참고 : 친구의 선언은 기능 또는 가까운 바깥 쪽 네임 스페이스의 구성원 클래스를 참조하지만, 그들은 새 이름을 소개하지 않는다 그 네임 스페이스에 넣는다 (7.3.1.2). 블록 범위와 블록 범위에서 통근 지정자 변수 선언에서 함수 선언은 둘러싸 네임 스페이스의 멤버 선언을 참조하지만, 그 범위에 새로운 이름을 소개하지 않습니다. 라고 §3.3.1/3 표준에서 : : -end 참고 여기서

+0

나는 그들이 * local scope *에 새로운 이름을 도입했다고 생각한다. 즉, 'extern int w;'는 일부 전역 변수를 참조하고 'int w;'는 로컬 범위의 새 객체를 정의합니다. 그래서 전역 변수를 가리키는'w'라는 이름과 지역 변수를 가리키는'w'라는 이름 사이에 충돌이 있습니다. – dyp

+0

§3.3.2/10이 방금 쓴 내용과 반대되는 말을하지 않습니까? –

+0

필자는 3.3.2/10을 "포함하는 네임 스페이스에 새 이름을 도입하지 않습니다"또는 "로컬 범위에 이름을 다시 도입하지만 * 새 * 이름을 입력하지 마십시오"로 해석합니다. – dyp

답변

7

은 대부분 §3.5/(6)에 의해 덮여있다. 특히

:

블록 범위 및 블록 범위 통근 선언 선언 변수 이름은 링크가 선언 함수의 이름. 동일한 이름 및 유형을 가진 연결이있는 엔터티의 보이는 선언이 있고 가장 안쪽에있는 네임 스페이스 범위 외부에서 선언 된 엔터티를 무시하면 블록 범위 선언은 동일한 엔터티를 선언하고 이전 선언의 연결을받습니다. 일치하는 엔티티가 둘 이상인 경우 프로그램이 잘못 구성됩니다. 일치하는 엔티티가 없으면 블록 범위 엔티티 이 외부 연결을 수신합니다. (일치하는 엔티티는 그 시점에서 볼 수 없기 때문에,이 경우의 외부 결합)

그래서 extern int w;가 결합되어있는 w을 선언한다.

은 그럼 당신은 (§3.5/8에 의해)에는 연결이없는 지역 w를 정의하는 시도합니다.

동일한 범위에서 동일한 이름의 두 선언을 제공

하지만, 다른 연결기로. 그는 §3.3.1/4에 의해 금지한다 :

같은 규정되지 않은 이름을 지정 각각 하나의 선언적 지역의 선언 세트,

  • 그들이 모두 같은 기업을 말한다을 감안할 때 , 또는 모두 함수 및 함수 템플릿을 참조하십시오. 또는
  • 정확히 하나의 선언은 typedef 이름이 아닌 클래스 이름 또는 열거 형 이름을 선언해야하며 이고 다른 선언은 모두 동일한 변수 또는 열거자를 참조해야하며, 모두 함수 및 함수 템플릿을 참조해야합니다. 이 경우 클래스 이름 또는 열거 형 이름은 숨겨집니다 (3.3.10).

어느 함수, 함수 템플릿, 클래스 이름 또는 열거 이름을 참조하므로 이러한 "탈출 조항 '중 어느 것도 적용되지 않습니다. 두 선언은 외부 엔티티와 링크가 모두없는 동일한 엔티티를 참조해야합니다. 그것이 불가능하기 때문에, 코드는 부적절합니다.

+0

다시 읽은 후, 저는 @dyp이 옳았고 3.3.1/4가 실제로 적용되는 부분이라고 생각합니다. 그에 따라 편집했습니다. –

+0

@JerryCoffin 늦어서 죄송합니다. 나는 두 시간 동안 책상에서 벗어났다. 나는 당신의 대답을 분석하기 전에 §3.5/6의 예를 이해하려고 노력하고 있습니다. 3 번 라인의 오브젝트가 정적 저장 기간과 외부 링크를 갖는 이유는 무엇입니까? 나는 이것을 위의 단락과 관련시킬 수 없다. 감사. –

+2

§3.5/6 (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#426)에 대한 결함 보고서가 있습니다 –

0

내 해석하는 선언으로 선언

이름은 선언이 발생하는 범위에 도입, 친구 지정자 (11.3)의 존재는, 정교 형 지정자 (7.1.6.3)을 사용하여-지침 (7.3.4)의 특정 사용이 일반적인 동작을 변경하는 것을 제외하고.

extern로 선언은 이름은 당신이 그것을 재 선언하려고 할 때이 오류가 왜 블록 범위에 도입, 예외로 나열되지 않습니다.

당신이 인용 된 단락은

을 말한다 그러나 그들은 그 범위에 새로운 이름을 소개하지 않습니다.

이는 블록 범위와 네임 스페이스 범위가 모두 언급되어 있기 때문에 약간 모호합니다. 표준이 범위를 가리키는 경우 모순됩니다. 따라서 네임 스페이스 범위를 의미한다고 가정합니다.내가 믿을

+0

예외는 [basic.link]/6-7 – dyp

+0

입니다. 이름을 다시 선언해도 반드시 오류는 아닙니다. 'extern int w; extern int w; extern int w;''w '를 세 번 선언하지만, 모든 선언문이 같은 엔티티를 참조하기 때문에 허용 가능합니다. – Casey