변수 초기화를 잘못 건너 뛰거나 정의되지 않은 동작을 유발합니까?


17

이 코드를 고려하십시오.

void foo()
{
    goto bar;
    int x = 0;
    bar: ;
}

GCC와 Clang 은 변수 초기화 를 건너 뛰기 때문에 이를 거부합니다bar: . MSVC는 (사용 제외하고는 전혀 불평하지 않습니다 xbar:원인 경고).

우리는 비슷한 일을 할 수 있습니다 switch:

void foo()
{
    switch (0)
    {
        int x = 0;
        case 0: ;
    }
}

이제 세 컴파일러 모두 오류가 발생합니다 .

스 니펫이 잘못 구성되어 있습니까? 아니면 UB를 유발합니까?

나는 둘 다 잘못 형성되었다고 생각했지만 표준의 관련 부분을 찾을 수 없습니다. [stmt.goto]은 이것에 대해 아무 말도하고도 수행하지 않습니다 [stmt.select] .


1
x점프 후 사용하면 문제가 더 사소한 것 입니다.
Jarod42

1
표준이 아니라 여기에 대한 정보를 찾을 수 있습니다. en.cppreference.com/w/cpp/language/goto 특히 : "제어 전송이 자동 변수의 범위에 들어간 경우 (예 : 선언을 뛰어 넘음) 성명), 프로그램이 잘못 작성되지 않은 경우 (컴파일 할 수 없음) ... "
idclev 463035818

/permissive-MSVC에 플래그를 추가하면 불만도 표시됩니다. 해당 플래그가없는 MSVC의 동작이 잘 정의되어 있는지 여부는 알 수 없습니다 (그렇다고 가정하면 그렇지 않은 이유는 무엇입니까?).
호두

@walnut "그렇지 않으면 왜 허용 하는가" 아마도 이전 버전과의 호환성을 위해 또는 표준에 너무 신경 쓰지 않기 때문일 수 있습니다. 모든 주요 컴파일러는 기본 설정에서 표준을 준수하지 않습니다.
HolyBlackCat

답변:


20

초기화가 비어 있지 않은 경우 잘못 구성됩니다.

[stmt.dcl]

3 초기화로 선언을 우회하는 방식 (조건 및 초기화 문의 선언 포함)으로 블록으로 전송할 수는 없습니다. 변수가 빈번한 초기화를하지 않으면 자동 저장 기간이있는 변수가 범위 내에 있지 않은 지점에서 범위 내에있는 지점으로 이동하는 프로그램입니다 ([basic.life]). 이 경우, 초기화가 빈번한 변수는 선언 순서대로 구성됩니다.

이니셜 라이저는 초기화를 비공식으로 만듭니다. 대조적으로, 이것은

void foo()
{
    goto bar;
    int x; // no initializer
    bar: ;
}

잘 형성 될 것입니다. x불확실한 가치로 사용 하는 것에 대한 일반적인 경고 가 적용 되지만 .


어쨌든 변수 선언이 범위에서 첫 번째 일 필요는 없습니까?
Cruncher

4
@Cruncher-C89가 필요했습니다. C ++은 결코하지 않았으며 더 이상 현대 C도 마찬가지입니다.
StoryTeller-Unslander Monica

3

에서 고토 문 :

제어 전송이 자동 변수의 범위에 들어간 경우 (예 : 선언문 위로 건너 뛰어) 범위를 입력 한 모든 변수가

  1. 이니셜 라이저없이 선언 된 스칼라 유형
  2. 간단한 기본 생성자와 이니셜 라이저없이 선언 된 간단한 소멸자가있는 클래스 유형
  3. 위 중 하나의 cv 인증 버전
  4. 위 중 하나의 배열
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.