IT이야기

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

cyworld 2022. 5. 25. 22:20
반응형

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

C와 C++에서 정의되지 않은 동작(UB)이란?지정되지 않은 동작과 구현 정의 동작은?그들 사이의 차이점은 무엇인가?

정의되지 않은 행동은 다른 언어에서 오는 프로그래머들에게 놀랄 수 있는 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문자열 리터럴을 가리키는 점"hello!\n"그리고 아래의 두 과제는 문자열을 리터럴로 수정하려고 시도한다.이 프로그램은 무엇을 하는가?C++ 표준의 2.14.5 섹션 11에 따라 정의되지 않은 동작을 발생시킨다.

문자열 리터럴을 수정하려는 효과는 정의되지 않았다.

사람들이 "하지만 기다려봐, 난 아무 문제 없이 컴파일해서 결과물을 얻을 수 있어."라고 외치는 소리가 들린다.yellow"또는 "정의되지 않은 문자열 리터럴이 읽기 전용 메모리에 저장되므로 첫 번째 할당 시도는 코어 덤프가 된다."이것이 바로 정의되지 않은 행동의 문제다.기본적으로 이 표준은 정의되지 않은 행동(비강 악령까지)을 발동하면 어떤 일이든 일어나게 한다.언어의 정신적 모델에 따라 "정확한" 행동이 있는 경우, 해당 모델은 단순히 잘못된 것이다.C++ 기준은 투표권, 기간밖에 없다.

정의되지 않은 동작의 다른 예로는 범위를 벗어난 어레이에 액세스하거나, null 포인터를 무시하거나, 수명이 끝난 객체에 액세스하거나, 다음과 같은 영리한 표현을 쓰는 것이 있다.i++ + ++i.

C++ 표준의 1.9절은 또한 정의되지 않은 행동의 덜 위험한 두 형제, 불특정 행동 및 구현 정의 행동을 언급한다.

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

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

추상적 기계의 특정한 다른 측면과 작동은 이 국제 표준에서 지정되지 않은 것으로 설명된다(예를 들어, 함수에 대한 인수의 평가 순서).가능한 경우 이 국제 표준은 일련의 허용 가능한 행동을 규정한다.이것들은 추상적인 기계의 비결정론적인 측면을 정의한다.

이 국제 표준에서 특정 다른 연산은 정의되지 않은 것으로 설명된다(예를 들어, null 포인터를 무시하는 효과).[: 이 국제 표준은 정의되지 않은 동작을 포함하는 프로그램의 동작에 대해 어떠한 요구사항도 부과하지 않는다.end note ]

특히 섹션 1.3.24에는 다음과 같이 명시되어 있다.

허용 가능한 정의되지 않은 동작은 예측 불가능한 결과를 가지고 상황을 완전히 무시하는 것에서부터 환경의 문서화된 방식으로 변환 또는 프로그램을 실행하는 동안 동작하는 것(진단 메시지 발행 여부와 무관), 변환 또는 실행을 종료하는 것(진단 메스 발행 포함)까지 다양하다.현자의

정의되지 않은 행동에 부딪히지 않기 위해 무엇을 할 수 있는가?기본적으로, 여러분은 그들이 무슨 이야기를 하는지 아는 작가들의 좋은 C++ 책을 읽어야 한다.인터넷 자습서를 사용하지 마십시오.불스차일드 피하십시오.

음, 이건 기본적으로 표준에서 직선으로 복사한 겁니다.

3.4.1 각 구현이 선택 방법을 문서화하는 구현 정의 동작 지정되지 않은 동작

2 사례 구현 정의 동작의 예로는 서명된 정수를 오른쪽으로 이동했을 때 고차 비트의 전파를 들 수 있다.

3.4.3 이 국제 표준이 어떤 요건을 부과하지 않는, 이동 가능하지 않거나 잘못된 프로그램 구성 또는 잘못된 데이터 사용 시 정의되지 않은 행동 행동 1개

2 참고 정의되지 않은 동작은 예측 불가능한 결과를 가지고 상황을 완전히 무시하는 것에서부터 환경의 특징인 문서화된 방식으로 변환 또는 프로그램을 실행하는 동안 동작하는 것(진단 메시지 발행 여부와 무관), 변환 또는 실행을 종료하는 것(진단 결과 발행 시)까지 다양하다.메시지).

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

3.4.4 1 이 국제 표준이 두 개 이상의 가능성을 제공하고 어떤 경우든 선택되는 추가 요건을 부과하지 않는 불특정 가치 또는 기타 행위의 지정되지 않은 행위 사용

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

아마도 표준의 엄격한 정의보다 쉬운 표현이 이해하기 쉬울 것이다.

구현 정의 동작
언어에 따르면 우리는 데이터 유형을 가지고 있다.컴파일러 공급업체는 어떤 크기를 사용해야 하는지 명시하고, 그들이 무엇을 했는지를 문서화한다.

정의되지 않은 행동
넌 뭔가 잘못하고 있어.예를 들어, 당신은 매우 큰 가치를 가지고 있다.int그것은 어울리지 않는다.char어떻게 그 가치를 넣는가?char사실 방법이 없어!무슨 일이든 일어날 수 있지만, 가장 현명한 것은 그 첫 번째 바이트를 입력해서 넣는 것일 것이다.char첫 번째 바이트를 할당하는 것은 잘못된 것이지만, 그것이 후드 아래에서 일어나는 일이다.

불특정 행동
이 두 가지 중 어떤 기능이 먼저 실행되는가?

void fun(int n, int m);

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

언어는 평가를 지정하지 않는다. 왼쪽에서 오른쪽으로 또는 오른쪽에서 왼쪽으로!그래서 불특정 행동들은 정의되지 않은 행동을 초래할 수도 있고 아닐 수도 있지만, 확실히 당신의 프로그램은 불특정 행동을 만들어내서는 안 된다.


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

을 위해fun(fun1(), fun2());그 행동은 "정확한 것"이 아닌가?컴파일러는 한 가지 코스를 선택해야 하고, 다른 코스를 선택해야 하는 거야, 결국?

구현 정의와 지정되지 않은 것의 차이는 컴파일러가 첫 번째 경우에는 동작을 선택하도록 되어 있지만 두 번째 경우에는 그렇지 않아도 된다는 것이다.예를 들어, 구현에는 다음 중 하나의 정의만 있어야 한다.sizeof(int).그러니까, 그렇다고는 할 수 없다.sizeof(int)프로그램의 일부는 4개, 다른 일부는 8개다.컴파일러가 OK라고 말할 수 있는 지정되지 않은 행동과 달리, 나는 이러한 주장을 좌우로 평가할 것이고 다음 함수의 주장은 좌우로 평가된다.같은 프로그램에서 일어날 수 있는 일인데, 그래서 불특정이라고 한다.사실 C++는 불특정 행위 중 일부를 특정했다면 더 쉽게 만들 수 있었을 것이다.여기 닥터 좀 봐에 대한 스트루스트럽의 대답은 다음과 같다.

컴파일러에게 이런 자유를 줄 수 있는 것과 '일반적인 좌우 평가'를 요구하는 것의 차이가 상당할 수 있다는 주장이다.나는 납득할 수 없지만, 셀 수 없이 많은 컴파일러들이 자유를 이용하고 그 자유를 열정적으로 옹호하고 있는 상황에서, 변화는 어려울 것이고 C와 C++ 세계의 먼 구석까지 침투하는데 수십 년이 걸릴 수 있다.나는 모든 컴파일러들이 다음과 같은 코드에 대해 경고하지 않아 실망했다.++i+i++. 마찬가지로 논쟁의 평가 순서도 불특정하다.

너무 많은 "물건"들이 정의되지 않고, 불특정하고, 말하기 쉽고, 심지어 예를 들기도 하지만 고치기 어렵다.또한 대부분의 문제를 피하고 휴대용 코드를 생산하는 것이 그렇게 어려운 일은 아니라는 점도 유의해야 한다.

구현 정의

구현자는 잘 문서화되어야 하며 표준은 선택사항을 제공하지만 컴파일할 것을 보장함

지정되지 않음 -

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

정의되지 않음

무슨 일이 있어도 잘 처리해라. 잘 처리해라.

공식 C 이론적 근거 문서로부터

불특정 행동, 정의되지 않은 행동 및 구현 정의 행동이라는 용어는 이 기준서가 완전하게 기술하지 않거나 기술할 수 없는 속성을 가진 프로그램 작성의 결과를 분류하기 위해 사용된다.이 분류를 채택하는 목적은 이 기준서의 준수 캐시를 제거하지 않고 구현 품질이 시장에서 활동적인 힘이 될 수 있도록 하는 구현 사이의 특정 다양성과 대중적인 특정 확대를 허용하는 것이다.이 기준서의 부록 F는 이 세 가지 범주 중 하나에 해당하는 행동을 분류한다.

지정되지 않은 동작은 프로그램 번역에 있어 구현자에게 약간의 관용을 준다.이 위도는 프로그램을 번역하지 않는 한 확장되지 않는다.

정의되지 않은 동작은 실행자가 진단하기 어려운 특정 프로그램 오류를 포착하지 못하도록 라이센스를 부여한다.또한 그것은 가능한 준수 언어 확장의 영역을 식별한다: 구현자는 공식적으로 정의되지 않은 행동에 대한 정의를 제공하여 언어를 증가시킬 수 있다.

구현 정의 동작은 구현자에게 적절한 접근방식을 선택할 자유를 주지만, 사용자에게 이 선택을 설명해야 한다.구현 정의로 지정된 동작은 일반적으로 사용자가 구현 정의에 기초하여 의미 있는 코딩 결정을 내릴 수 있는 동작이다.이행자는 이행 정의가 얼마나 광범위해야 하는지를 결정할 때 이 기준을 명심해야 한다.불특정 행동과 마찬가지로, 단순히 구현 정의 행동을 포함하는 소스를 번역하지 않는 것은 적절한 대응이 아니다.

정의되지 않은 동작 vs. 불특정 행동에는 그것에 대한 짧은 설명이 있다.

최종 요약:

요약하자면, 소프트웨어를 휴대할 필요가 없는 경우가 아니라면, 지정되지 않은 행동은 보통 걱정해서는 안 되는 것이다.반대로 정의되지 않은 행동은 항상 바람직하지 않으며 절대 일어나서는 안 된다.

역사적으로, 구현 정의 행동과 정의되지 않은 행동 모두 이 기준서의 작성자들이 품질 구현을 작성하는 사람들이 어떤 행동 보장이 의도된 목표에서 실행되는 의도된 애플리케이션 분야의 프로그램에 유용한지를 결정하기 위해 판단을 사용할 것으로 예상한 상황을 나타낸다.하이엔드 번호 크런치 코드의 니즈는 로우 레벨 시스템 코드의 니즈와 상당히 다르며, 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;
}

두 사람이 공동으로 시행하면 그 표현을 다루기 위해 어떤 노력도 할 필요가 없을 것이다.v << pow의 여부를 고려하지 않고 두 사람의 교대로서.v긍정적이거나 부정적이었습니다.

그러나 오늘날 컴파일러 작가들 중 몇몇이 선호하는 철학은 다음과 같은 이유를 제시한다.v프로그램이 정의되지 않은 행동을 할 경우에만 음성이 될 수 있으며, 프로그램의 부정적인 범위를 클리핑하도록 할 이유가 없다.v과거엔 유의성의 모든 컴파일러에 대해 부정적 값의 좌변형이 지원되었고, 기존 코드의 많은 양이 그러한 행동에 의존했음에도 불구하고, 현대 철학은 좌변화가 부정적 가치의 좌변화는 UB라고 하는 사실을 컴파일러 작성자들이 그것을 무시해도 무방할 것임을 암시하는 것으로 해석할 것이다.

정의되지 않은 행동은 추악하다. "좋은 것, 나쁜 것, 추한 것"에서와 같이.

좋은: 올바른 이유로 컴파일하고 작동하는 프로그램.

Bad: 컴파일러가 감지하고 불평할 수 있는 종류의 오류가 있는 프로그램.

못생긴 프로그램: 컴파일러가 감지하고 경고할 수 없는 오류가 있는 프로그램, 즉 프로그램이 컴파일러를 구성하고, 어떤 때는 제대로 작동하는 것처럼 보이지만, 어떤 때는 이상하게 실패하기도 한다.정의되지 않은 행동이 바로 그것이다.

일부 프로그램 언어와 다른 공식 시스템은 "미정의 골프"를 제한하기 위해 열심히 노력한다. 즉, 대부분의 또는 모든 프로그램이 "좋다"거나 "나쁘다"거나 "나쁘다"는 극소수의 프로그램들이 "불확실성의 골프"를 가지도록 물건들을 배열하려고 한다.그러나 C의 "미정의 골프"가 상당히 넓다는 것은 C의 특징이다.

C++ standard n3337 § 1.3.10 implementation-defined behavior

behavior, for a well-formed program construct and correct data, that depends on the implementation and that each implementation documents

Sometimes C++ Standard doesn't impose particular behavior on some constructs but says instead that a particular, well defined behavior has to be chosen and described by particular implementation (version of library). So user can still know exactly how will program behave even though Standard doesn't describe this.


C++ standard n3337 § 1.3.24 undefined behavior

behavior for which this International Standard imposes no requirements [ Note: Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. — end note ]

When the program encounters construct that is not defined according to C++ Standard it is allowed to do whatever it wants to do ( maybe send an email to me or maybe send an email to you or maybe ignore the code completely).


C++ standard n3337 § 1.3.25 unspecified behavior

behavior, for a well-formed program construct and correct data, that depends on the implementation [ Note: The implementation is not required to document which behavior occurs. The range of possible behaviors is usually delineated by this International Standard. — end note ]

C++ Standard doesn't impose particular behavior on some constructs but says instead that a particular, well defined behavior has to be chosen ( bot not necessary described) by particular implementation (version of library). So in the case when no description has been provided it can be difficult to the user to know exactly how will program behave.

참조URL: https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior

반응형