정의되지 않은 지정되지 않은 구현 정의 동작


530

C 및 C ++에서 정의되지 않은 동작은 무엇입니까? 지정되지 않은 동작 및 구현 정의 동작은 어떻습니까? 그들 사이의 차이점은 무엇입니까?


1
나는 우리 가이 befor을 먹었을 것이라고 확신했지만 그것을 찾을 수는 없다. 참조 : stackoverflow.com/questions/2301372/...
dmckee --- 전 사회자 고양이



1
다음은 흥미로운 토론입니다 ( "부록 L 및 정의되지 않은 동작"섹션).
Owen

답변:


405

정의되지 않은 동작 은 다른 언어에서 온 프로그래머들에게 놀라운 C 및 C ++ 언어 측면 중 하나입니다 (다른 언어에서는 더 잘 숨기려고합니다). 기본적으로 많은 C ++ 컴파일러가 프로그램의 오류를보고하지 않더라도 예측 가능한 방식으로 동작하지 않는 C ++ 프로그램을 작성할 수 있습니다!

고전적인 예를 보자.

#include <iostream>

int main()
{
    char* p = "hello!\n";   // yes I know, deprecated conversion
    p[0] = 'y';
    p[5] = 'w';
    std::cout << p;
}

변수 p는 문자열 literal을 가리키고 "hello!\n"아래 두 할당은 해당 문자열 리터럴을 수정하려고합니다. 이 프로그램은 무엇을합니까? C ++ 표준의 2.14.5 단락 11에 따르면 정의되지 않은 동작을 호출합니다 .

문자열 리터럴을 수정하려는 결과는 정의되지 않습니다.

사람들이 비명을 지르는 것을들을 수 있습니다. "잠깐만,이 문제를 컴파일하지 않고 결과를 얻을 수 있습니다. yellow 마세요. "또는 "정의되지 않은 문자열 리터럴이 읽기 전용 메모리에 저장되어 있으므로 첫 번째 할당 시도로 인해 코어 덤프가 발생합니다." 이것은 정의되지 않은 동작의 문제입니다. 기본적으로이 표준은 정의되지 않은 동작 (비강 악마 포함)을 호출하면 어떤 일이든 발생할 수 있습니다. 언어의 당신의 정신 모델에 따라 "올바른"행동이 있다면, 그 모델은 단순히 잘못된 것입니다; C ++ 표준은 유일한 투표 기간을 갖습니다.

정의되지 않은 동작의 다른 예로는 경계를 넘어 배열에 액세스하거나 , 널 포인터를 역 참조하거나 , 수명이 끝난 후 오브젝트액세스 하거나, 영리한 식을 쓰는 등 이 i++ + ++i있습니다.

C ++ 표준의 섹션 1.9에는 정의되지 않은 동작의 덜 위험한 두 형제, 지정되지 않은 동작구현 정의 된 동작 도 언급 되어 있습니다 .

이 국제 표준의 의미 론적 설명은 매개 변수화 된 비결정론 적 추상 기계를 정의합니다.

추상 기계의 특정 측면과 작동은이 국제 표준에서 구현 정의 (예 :)로 설명됩니다 sizeof(int). 이것들은 추상 기계의 매개 변수를 구성합니다. 각 구현에는 이러한 점에서 특성과 동작을 설명하는 문서가 포함되어야합니다.

추상 기계의 어떤 다른 측면들 및 동작들은이 국제 표준에서 지정되지 않은 것으로 기술 되어있다 (예를 들어, 함수에 대한 인수의 평가 순서). 가능한 경우이 국제 표준은 허용 가능한 동작 집합을 정의합니다. 이것들은 추상 기계의 비 결정적 측면을 정의합니다.

다른 국제 오퍼레이션은이 국제 표준에서 정의되지 않은 것으로 설명됩니다 (예 : 널 포인터 역 참조의 영향). [ 참고 : 이 국제 표준은 정의되지 않은 동작을 포함하는 프로그램의 동작에 대한 요구 사항을 부과하지 않습니다. 끝 참고 ]

특히 1.3.24 절에는 다음과 같이 명시되어 있습니다.

허용되지 않는 정의 된 행동은 예측할 수없는 결과로 상황을 완전히 무시하는 것에서부터 환경의 특성화 된 문서화 된 방식으로 진단 또는 프로그램 실행 중 동작 (진단 메시지 발행 여부에 관계없이), 번역 또는 실행 종료 (발급 포함)에 이르기까지 다양 합니다. 진단 메시지).

정의되지 않은 동작을 피하기 위해 무엇을 할 수 있습니까? 기본적으로, 당신은 그들이 무엇을 말하는지 알고있는 저자에 의해 좋은 C ++ 책 을 읽어야 합니다. 인터넷 자습서를 조이십시오. 스크류 불스 어린이.


6
이 답변은 C ++에만 적용되지만이 질문의 태그에는 C가 포함된다는 병합의 결과로 이상한 사실입니다. C에는 "정의되지 않은 동작"이라는 다른 개념이 있습니다. 특정 규칙 위반 (제약 위반)에 대해서는 정의되지 않아야합니다.
Johannes Schaub-litb

8
@Benoit 표준에 정의되지 않은 동작, 기간이 표시되어 있기 때문에 정의되지 않은 동작입니다. 일부 시스템에서는 실제로 문자열 리터럴이 읽기 전용 텍스트 세그먼트에 저장되며 문자열 리터럴을 수정하려고하면 프로그램이 중단됩니다. 다른 시스템에서는 문자열 리터럴이 실제로 변경되어 나타납니다. 이 표준은 발생해야 할 사항을 요구하지 않습니다. 이것이 정의되지 않은 행동의 의미입니다.
fredoverflow 2012 년

5
@FredOverflow, 왜 좋은 컴파일러가 정의되지 않은 동작을 제공하는 코드를 컴파일 할 수있게합니까? 정확히 어떤 좋은 것은 코드주고 이런 종류의 컴파일 할 수 있습니까? 정의되지 않은 동작을 제공하는 코드를 컴파일하려고 할 때 왜 모든 좋은 컴파일러가 우리에게 커다란 적색 경고 신호를주지 않았습니까?
Pacerier

14
@Pacerier 컴파일 타임에 확인할 수없는 것이 있습니다. 예를 들어, 널 포인터가 절대로 역 참조되지 않을 수는 있지만 항상 정의되지는 않습니다.
Tim Seguine 2014

4
@Celeritas, 정의되지 않은 동작 비 결정적 일 있습니다. 예를 들어, 초기화되지 않은 메모리의 내용이 무엇인지 미리 알 수는 없습니다. int f(){int a; return a;}: a함수 호출간에 값 이 변경 될 수 있습니다.
Mark

97

글쎄, 이것은 기본적으로 표준에서 직접 복사하여 붙여 넣습니다.

3.4.1 1 구현-정의 된 행동 지정되지 않은 행동 - 각 구현이 선택 방법을 문서화 함

2 예 구현 정의 된 동작의 예는 부호있는 정수가 오른쪽으로 이동 될 때 상위 비트의 전파입니다.

3.4.3 1 비 이동식 또는 잘못된 프로그램 구성 또는 잘못된 데이터 사용시 정의되지 않은 행동 거동

2 참고 가능한 정의되지 않은 행동은 예측할 수없는 결과로 상황을 완전히 무시하는 것부터, 환경의 특성화 된 문서화 된 방식으로 (진단 메시지 발행 여부에 관계없이) 번역 또는 프로그램 실행 중 행동, 번역 또는 실행 종료 진단 메시지 발행).

3 예 정의되지 않은 동작의 예는 정수 오버플로에서의 동작입니다.

3.4.4 1 불특정 행동 불특정 가치의 사용, 또는이 표준이 두 가지 이상의 가능성을 제공하고 어떠한 경우에도 더 이상 요구되지 않는 다른 행동

2 예 지정되지 않은 동작의 예는 함수에 대한 인수가 평가되는 순서입니다.


3
구현 정의 동작과 지정되지 않은 동작의 차이점은 무엇입니까?
Zolomon

26
@ Zolomon : 말 그대로 : 구현 정의의 경우 구현이 정확히 일어날 일을 문서화하는 것을 요구한다는 것을 제외하고는 기본적으로 동일한 것입니다. 지정되지 않은 경우 구현은 문서화 할 필요가 없습니다 또는 아무것도 보증하지 않습니다.
AnT

1
@ Zolomon : 3.4.1과 2.4.4의 차이에 반영됩니다.
sbi

8
@Celeritas : 하이퍼 현대 컴파일러는 그보다 더 잘 할 수 있습니다. 을 감안할 때 int foo(int x) { if (x >= 0) launch_missiles(); return x << 1; }정의되지 않은 동작 호출하는 미사일을 발사하지 않는 함수를 호출하는 모든 수단 때문에,이 호출 할 수 있음을 확인할 수 있습니다 컴파일러 launch_missiles()무조건입니다.
supercat

2
@northerner 인용문에서 알 수 있듯이 지정되지 않은 동작은 일반적으로 제한된 동작 집합으로 제한됩니다. 어떤 경우에는 주어진 맥락에서 이러한 가능성을 모두 수용 할 수 있다는 결론을 내릴 수도 있습니다.이 경우 지정되지 않은 동작은 전혀 문제가되지 않습니다. 정의되지 않은 동작은 완전히 제한되지 않습니다 (예 : "프로그램이 하드 드라이브를 포맷하기로 결정할 수 있음"). 정의되지 않은 동작은 항상 문제입니다.
AnT

60

표준에 대한 엄격한 정의보다 이해하기 쉬운 표현이 더 쉬울 수 있습니다.

구현 정의 동작
언어에는 데이터 유형이 있다고 말합니다. 컴파일러 공급 업체는 사용할 크기를 지정하고 수행 한 작업에 대한 문서를 제공합니다.

정의되지 않은 동작
문제가 있습니다. 예를 들어에 int맞지 않는 값이 매우 큽니다 .char . 그 가치를 char어떻게 넣 습니까? 실제로 방법은 없습니다! 어떤 일이든 일어날 수 있지만 가장 현명한 것은 int의 첫 번째 바이트를 가져 와서 넣는 것입니다 char. 첫 번째 바이트를 할당하는 것은 잘못된 일이지만 그 결과는 후드 아래에서 발생합니다.

불특정 행동
이 두 기능 중 어떤 기능이 먼저 실행됩니까?

void fun(int n, int m);

int fun1()
{
  cout << "fun1";
  return 1;
}
int fun2()
{
  cout << "fun2";
  return 2;
}
...
fun(fun1(), fun2()); // which one is executed first?

언어는 왼쪽에서 오른쪽으로 또는 오른쪽에서 왼쪽으로 평가를 지정하지 않습니다! 따라서 지정되지 않은 동작은 정의되지 않은 동작을 초래하거나 발생하지 않을 수 있지만 프로그램에서 지정되지 않은 동작을 생성해서는 안됩니다.


@ eSKay 나는 당신의 질문이 더 명확하게 답변을 편집 할 가치가 있다고 생각합니다 :)

...에 대한 fun(fun1(), fun2()); 행동 "구현 정의 된"아닌가요? 컴파일러는 결국 하나 또는 다른 코스를 선택해야합니까?

구현 정의와 지정되지 않은 차이점은 컴파일러가 첫 번째 경우 동작을 선택해야하지만 두 번째 경우에는 필요하지 않다는 것입니다. 예를 들어, 구현에는의 정의가 하나만 있어야합니다 sizeof(int). 따라서 sizeof(int)프로그램의 일부에서는 4이고 다른 것은 8 이라고 말할 수 없습니다 . 컴파일러가 OK라고 말할 수있는 지정되지 않은 동작과 달리이 인수를 왼쪽에서 오른쪽으로 평가하고 다음 함수의 인수를 오른쪽에서 왼쪽으로 평가합니다. 동일한 프로그램에서 발생할 수 있으므로 unspecified 라고 합니다. 실제로 지정되지 않은 동작 중 일부를 지정하면 C ++가 더 쉬워 질 수 있습니다. Stroustrup 박사의 답변을 여기에서 살펴보십시오. .

컴파일러에게 이러한 자유를 제공하고 "일반적인 왼쪽에서 오른쪽 평가"를 요구하는 것의 차이는 중요 할 수 있다고 주장됩니다. 나는 확신 할 수 없지만 자유를 활용하는 무수한 컴파일러가 있고 자유를 열정적으로 지키는 일부 사람들이 있다면 변화가 어려울 수 있으며 C와 C ++ 세계의 먼 구석에 침투하는 데 수십 년이 걸릴 수 있습니다. 모든 컴파일러가 ++ i + i ++와 같은 코드에 대해 경고하는 것은 아닙니다. 마찬가지로, 인수 평가 순서는 지정되어 있지 않습니다.

IMO가 너무 많은 "사물"은 정의되지 않은, 지정되지 않은, 구현 정의 된 등으로 남아 있습니다. 그러나 그것은 말하기 쉽고 예를 제시하기는 어렵지만 수정하기는 어렵습니다. 또한 대부분의 문제를 피하고 이식 가능한 코드를 생성하는 것이 어려운 것은 아닙니다.


1
에 대한 fun(fun1(), fun2());동작은하지 않습니다 "implementation defined"? 컴파일러는 결국 하나 또는 다른 코스를 선택해야합니까?
Lazer

1
@AraK : 설명해 주셔서 감사합니다. 이해합니다. Btw, "I am gonna evaluate these arguments left-to-right and the next function's arguments are evaluated right-to-left"나는 이것이 can일어나는 것을 이해합니다 . 요즘 우리가 사용하는 컴파일러를 사용합니까?
Lazer

1
@eSKay 많은 컴파일러로 손을 더럽힌 전문가에 대해 전문가에게 문의해야합니다. :) AFAIK VC는 항상 오른쪽에서 왼쪽으로 인수를 평가합니다.
AraK

4
@Lazer : 확실히 일어날 수 있습니다. 간단한 시나리오 : foo (bar, boz ()) 및 foo (boz (), bar). 여기서 bar는 int이고 boz ()는 int를 반환하는 함수입니다. 매개 변수가 레지스터 R0-R1에 전달 될 것으로 예상되는 CPU를 가정하십시오. 함수 결과는 R0에 리턴됩니다. 기능이 R1을 손상시킬 수 있습니다. "boz ()"전에 "bar"를 평가하려면 boz ()를 호출 한 다음 저장된 사본을로드하기 전에 다른 곳에 사본을 저장해야합니다. "boz ()"다음에 "bar"를 평가하면 메모리 저장 및 다시 가져 오기를 피할 수 있으며 인수 목록의 순서에 관계없이 많은 컴파일러가 수행하는 최적화입니다.
supercat

6
C ++에 대해서는 모르겠지만 C 표준에 따르면 int를 char로 변환하는 것은 구현이 정의되었거나 잘 정의되어 있습니다 (실제 값과 유형의 부호에 따라 다름). C99 §6.3.1.3 (C11에서 변경되지 않음)을 참조하십시오.
Nikolai Ruhe

27

공식 C 근거 문서에서

지정되지 않은 동작, 정의되지 않은 동작 및 구현 정의 된 동작 이라는 용어 는 표준 속성이 완전히 설명 할 수 없거나 완전히 설명 할 수없는 프로그램 작성 결과를 분류하는 데 사용됩니다. 이 분류를 채택하는 목적은 표준에 따른 적합성을 제거하지 않고도 구현 품질을 시장에서 적극적으로 강화할 수있을뿐만 아니라 시장에서 활발한 힘을 발휘할 수 있도록하는 다양한 구현을 허용하는 것입니다. 표준에 대한 부록 F는 이러한 세 가지 범주 중 하나에 해당하는 행동을 정리합니다.

지정되지 않은 동작 은 구현 자에게 프로그램을 번역 할 때 위도를 제공합니다. 이 위도는 프로그램을 번역하지 못하는 한 확장되지 않습니다.

정의되지 않은 동작 은 구현 자에게 진단하기 어려운 특정 프로그램 오류를 포착하지 못하도록 라이센스를 부여합니다. 또한 가능한 언어 확장이 가능한 영역을 식별합니다. 구현자는 공식적으로 정의되지 않은 동작의 정의를 제공하여 언어를 보강 할 수 있습니다.

구현 정의 동작은 구현 자 에게 적절한 접근 방식을 선택할 수있는 자유를 제공하지만이 선택은 사용자에게 설명해야합니다. 구현 정의로 지정된 동작은 일반적으로 사용자가 구현 정의에 따라 의미있는 코딩 결정을 내릴 수있는 동작입니다. 구현자는 구현 정의의 범위를 결정할 때이 기준을 명심해야합니다. 지정되지 않은 동작과 마찬가지로 구현 정의 동작을 포함하는 소스를 변환하지 못하는 것만으로는 적절하지 않습니다.


3
하이퍼 현대 컴파일러 작성자는 또한 "정의되지 않은 동작"을 컴파일러 작성자에게 프로그램이 정의되지 않은 동작을 유발하는 입력을 수신하지 않을 것이라고 가정하고 프로그램이 이러한 입력을 수신 할 때 동작하는 방식의 모든 측면을 임의로 변경할 수있는 라이센스를 부여하는 것으로 간주합니다.
supercat

2
방금 주목 한 또 다른 요점 : C89는 "확장"이라는 용어를 사용하여 일부 구현에서는 보장되었지만 다른 구현에서는 보장되지 않는 기능을 설명하지 않았습니다. C89의 저자는 당시의 대부분의 구현이 결과가 특정 방식으로 사용 된 경우를 제외하고는 부호있는 산술 연산과 부호없는 산술 연산을 동일하게 처리 할 것이며, 그러한 처리는 부호있는 오버플로의 경우에도 적용됨을 인식했습니다. 그들은 그것을 부속서 J2의 공통된 확장으로 열거하지 않았는데, 이것은 그것이 확장이 아니라 자연스러운 상태로 본다는 것을 암시한다.
슈퍼 캣

10

정의되지 않은 동작과 지정되지 않은 동작 에 대한 간단한 설명이 있습니다.

그들의 최종 요약 :

요약하면, 지정되지 않은 동작은 일반적으로 소프트웨어를 이식 할 수있는 경우가 아니라면 걱정하지 않아도됩니다. 반대로, 정의되지 않은 동작은 항상 바람직하지 않으며 절대 발생하지 않아야합니다.


1
두 가지 종류의 컴파일러가 있습니다. 명시 적으로 달리 문서화되어 있지 않은 한, 표준의 정의되지 않은 행동 양식의 대부분은 기본 환경에 의해 문서화 된 특징적인 행동으로 되돌아가는 것으로 해석되며, 기본적으로 표준이 특징 짓는 행동 만 유용하게 노출시키는 것입니다. 구현 정의. 첫 번째 유형의 컴파일러를 사용할 때 첫 번째 유형의 많은 작업을 UB를 사용하여 효율적이고 안전하게 수행 할 수 있습니다. 두 번째 유형의 컴파일러는 이러한 경우 동작을 보장하는 옵션을 제공하는 경우에만 해당 작업에 적합합니다.
supercat

8

역사적으로, 구현 정의 행동과 정의되지 않은 행동은 표준 구현 자들이 품질 구현을 작성하는 사람들이 판단을 사용하여 행동 보장이있을 경우 어떤 행동 보장이 응용 프로그램에서 실행되는 의도 된 응용 분야의 프로그램에 도움이 될지를 결정할 것으로 예상하는 상황을 나타 냈습니다. 의도 된 목표. 하이 엔드 숫자 처리 코드의 요구는 저수준 시스템 코드의 요구와는 매우 다르며, UB와 IDB는 컴파일러 작성자에게 다양한 요구를 충족시킬 수있는 유연성을 제공합니다. 범주는 구현이 특정 목적이나 어떤 목적에도 유용한 방식으로 작동하도록 요구하지 않습니다. 그러나 특정 목적에 적합하다고 주장하는 품질 구현은 그러한 목적에 맞는 방식으로 행동해야합니다표준이 요구하는지의 여부 .

구현-정의 된 행동과 정의되지 않은 행동의 유일한 차이점은 전자가 구현 이 도움이 될 수없는 경우에도 일관된 행동을 정의하고 문서화해야한다는 점 이다 . 이들 사이의 구분선은 일반적으로 구현에서 동작을 정의하는 것이 유용한 지 여부 (컴파일러 작성자가 표준에서 요구하는지 여부에 관계없이 유용한 동작을 정의해야 함)가 아니라 동작 정의가 동시에 비용이 많이 드는 구현이 있는지 여부입니다. 쓸모없는 . 이러한 구현이 존재할 수 있다는 판단은 어떤 방식, 형태 또는 형태로도 다른 플랫폼에서 정의 된 동작을 지원하는 데 유용하다는 판단을 내포하지 않습니다.

불행하게도, 1990 년대 중반부터 컴파일러 제작자들은 행동 보장의 부족이 행동 보장이 중요하지 않은 응용 분야와 실질적으로 비용이 들지 않는 시스템에서도 비용 가치가 없다는 판단으로 해석하기 시작했습니다. UB를 합리적인 판단의 초청으로 취급하는 대신 컴파일러 작성자는 UB 를 그렇게하지 않는 변명으로 취급하기 시작했습니다 .

예를 들어 다음 코드가 제공됩니다.

int scaled_velocity(int v, unsigned char pow)
{
  if (v > 250)
    v = 250;
  if (v < -250)
    v = -250;
  return v << pow;
}

2의 보수 구현 은 긍정적이든 부정적 v << pow이든 상관없이 표현 을 2의 보수 교대로 취급하기 위해 어떠한 노력도 들일 필요가 없습니다 v.

그러나 오늘날의 컴파일러 작성자 중 선호되는 철학 v은 프로그램이 정의되지 않은 동작에 관여하는 경우에만 음수 일 수 있기 때문에 프로그램의 음수 범위를 음수 범위로 지정할 이유가 없습니다 v. 음수 값의 왼쪽 이동이 모든 단일 컴파일러에서 지원되는 데 사용되었지만 기존 코드의 상당수가 해당 동작에 의존하지만 현대 철학은 왼쪽 이동 음수 값이 다음과 같이 UB라는 사실을 표준에서 해석합니다. 컴파일러 작성자가이를 무시해도된다는 것을 암시합니다.


그러나 정의되지 않은 행동을 멋지게 처리하는 것은 무료가 아닙니다. 현대 컴파일러가 UB의 일부 경우에 기괴한 동작을 나타내는 전체 이유는 그들이 끊임없이 최적화하고 있으며 최선을 다하기 위해서는 UB가 절대 발생하지 않는다고 가정해야하기 때문입니다.
Tom Swirly

그러나 <<음수에 UB 라는 사실 은 불쾌한 작은 함정이며 그 사실을 기억하게되어 기쁩니다!
Tom Swirly

1
@TomSwirly : 불행히도, 컴파일러 작성자는 표준에 의해 규정 된 것보다 느슨한 동작 보장을 제공 할 경우 표준에 의해 정의되지 않은 모든 비용을 코드가 피하도록 요구하는 것에 비해 속도가 크게 향상 될 수 있다는 점에 신경 쓰지 않습니다. i+j>k추가 부작용이없는 경우 프로그래머가 1 또는 0을 생성 하는지 여부를 신경 쓰지 않으면 다른 부작용이 없다면 컴파일러는 프로그래머가 코드를 다음과 같이 작성하면 불가능한 대규모 최적화를 수행 할 수 있습니다 (int)((unsigned)i+j) > k.
supercat

1
@TomSwirly : 컴파일러 X가 엄격한 작업을 수행하여 일부 작업 T를 수행하고 컴파일러 Y가 동일한 프로그램으로 생성하는 것보다 5 % 더 효율적인 실행 파일을 생성 할 수 있다면 Y가더라도 X가 더 좋습니다. Y는 보장하지만 X는 보장하지 않는 행동을 이용하는 프로그램이 주어지면 동일한 작업을 세 번 수행하는 코드를 생성 할 수 있습니다.
supercat

6

C ++ 표준 n3337 § 1.3.10 구현 정의 동작

구현 및 각 구현 문서에 따라 올바르게 구성된 프로그램 구성 및 올바른 데이터에 대한 동작

때로는 C ++ Standard는 일부 구문에 특정 동작을 부과하지 않지만 대신 특정 구현 (라이브러리 버전)에 의해 잘 정의 된 특정 동작을 선택하고 설명 해야한다고 말합니다 . 따라서 표준에서 설명하지 않아도 사용자는 프로그램이 어떻게 작동하는지 정확하게 알 수 있습니다.


C ++ 표준 n3337 § 1.3.24 정의되지 않은 동작

이 국제 표준이 요구 사항을 부과하지 않는 행동 [참고 :이 국제 표준이 명시적인 행동 정의를 생략하거나 프로그램이 잘못된 구성 또는 잘못된 데이터를 사용하는 경우 정의되지 않은 동작이 예상 될 수 있습니다. 허용되지 않는 정의 된 동작은 예측할 수없는 결과로 상황을 완전히 무시하는 것부터, 환경의 특성화 된 문서화 된 방식으로 진단 또는 프로그램 실행 중 (진단 메시지 발행 여부에 관계없이), 번역 또는 실행 종료 (발급 포함)에 이르기까지 다양합니다. 진단 메시지). 많은 잘못된 프로그램 구성은 정의되지 않은 동작을 유발하지 않습니다. 그들은 진단을 받아야합니다. — 끝 참고]

프로그램에서 C ++ 표준에 따라 정의되지 않은 구문을 발견하면 원하는대로 수행 할 수 있습니다 (이메일을 보내거나 이메일을 보내거나 코드를 완전히 무시할 수 있음).


C ++ 표준 n3337 § 1.3.25 지정되지 않은 동작

구현에 의존하는 올바른 형식의 프로그램 구성 및 올바른 데이터에 대한 동작 [참고 : 구현은 어떤 동작이 발생하는지 문서화 할 필요가 없습니다. 가능한 행동의 범위는 일반적으로이 국제 표준에 의해 묘사됩니다. — 끝 참고]

C ++ Standard는 일부 구문에 특정 동작을 부과하지 않지만 대신 특정 구현 (라이브러리 버전)에 의해 잘 정의 된 특정 동작을 선택해야한다고 말합니다 ( 봇은 필요하지 않음 ). 따라서 설명이 제공되지 않은 경우 사용자는 프로그램의 작동 방식을 정확히 이해하기가 어려울 수 있습니다.


6

구현 정의

구현자는 원하는 문서를 잘 작성해야하며 표준은 선택을 제공하지만 반드시 컴파일해야합니다.

불특정-

구현 정의와 동일하지만 문서화되지 않음

찾으시는 주소가 없습니다-

어떤 일이든 일어날 수 있습니다.


2
"정의되지 않은"의 실제 의미가 지난 몇 년 동안 바뀌 었다는 점에 주목하는 것이 중요하다고 생각합니다. 예전 에는 33 일 때를 uint32_t s;평가 1u<<s하면 s0을 산출하거나 2를 산출 할 것으로 예상되지만 별다른 것은하지 않습니다. 그러나 최신 컴파일러를 평가 1u<<s하면 컴파일러 s는 사전에 32 개 미만이어야 했기 때문에 s32 개 이상인 경우에만 해당되는 식의 전후에있는 코드를 생략 할 수 있다고 컴파일러가 판단 할 수 있습니다.
supercat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.