왜 'd / = d'는 d == 0 일 때 0으로 나누기 예외를 발생시키지 않습니까?
제로 예외로 나누지 못하는 이유를 잘 모르겠습니다.
int d = 0;
d /= d;
제로 예외로 나누기를 기대했지만 대신 d == 1
.
왜 d /= d
0으로 나누기 예외가 발생하지 d == 0
않습니까?
C ++에는 "0으로 나누기"예외가 없습니다. 관찰중인 동작은 컴파일러 최적화의 결과입니다.
- 컴파일러는 정의되지 않은 동작이 발생하지 않는다고 가정합니다.
- C ++에서 0으로 나누기는 정의되지 않은 동작입니다.
- 따라서 Division by Zero를 유발할 수 있는 코드 는 그렇지 않은 것으로 추정됩니다.
- 그리고 Division by Zero를 유발 해야하는 코드 는 발생하지 않는 것으로 추정됩니다.
- 따라서 컴파일러는 Undefined Behavior가 발생하지 않기 때문에이 코드 (
d == 0
)의 Undefined Behavior 조건이 발생하지 않아야한다고 추론합니다. - 따라서
d / d
항상 1이어야합니다.
하나...
컴파일러가 코드를 약간만 변경하여 "실제"나누기를 0으로 트리거하도록 할 수 있습니다.
volatile int d = 0;
d /= d; //What happens?
이제 질문이 남아 있습니다. 기본적으로 컴파일러가이를 허용하도록 강제 했으므로 어떻게됩니까? 정의되지 않은 동작이지만 이제 컴파일러가이 정의되지 않은 동작을 최적화하는 것을 방지했습니다.
대부분 대상 환경에 따라 다릅니다. 이 소프트웨어 예외를 트리거하지 않습니다,하지만 수 하드웨어 예외를 트리거 (타겟 CPU에 따라 다름) (정수-으로 나누기) 소프트웨어 예외가 잡힐 수있는 전통 방식으로 잡은 할 수 없습니다. 이것은 x86 CPU와 대부분의 다른 (전부는 아닙니다!) 아키텍처의 경우입니다.
그러나 프로그램 충돌을 허용하는 대신 하드웨어 예외를 처리하는 방법이 있습니다 (발생하는 경우) : 적용 가능한 몇 가지 방법에 대해서는이 게시물을 참조하십시오. 예외 잡기 : 0으로 나누기 . 컴파일러마다 다릅니다.
다른 답변을 보완하기 위해 0으로 나누는 것이 정의되지 않은 동작이라는 사실 은 컴파일러가 어떤 일이 발생할 경우 자유롭게 할 수 있음을 의미합니다 .
- 컴파일러는이를 가정하고
0 / 0 == 1
그에 따라 최적화 할 수 있습니다 . 그것이 실제로 여기에서 한 것처럼 보입니다. - 컴파일러는 원하는 경우이를 가정하고 해당 값으로
0 / 0 == 42
설정할 수도d
있습니다. - 컴파일러는 또한의 값
d
이 불확정 하다고 결정할 수 있으므로 변수를 초기화되지 않은 상태로 두어 해당 값은 이전에 할당 된 메모리에 기록 된 값이됩니다. 주석의 다른 컴파일러에서 관찰 된 예상치 못한 값 중 일부는 이러한 컴파일러가 이와 같은 작업을 수행함으로써 발생할 수 있습니다. - 컴파일러는 0으로 나누기가 발생할 때마다 프로그램을 중단하거나 예외를 발생시킬 수도 있습니다. 이 프로그램의 경우 컴파일러는 이것이 항상 발생할 것이라고 판단 할 수 있으므로 코드를 생성하여 예외를 발생시키고 (또는 실행을 완전히 중단하고) 나머지 함수를 도달 할 수없는 코드로 처리 할 수 있습니다.
- 0으로 나누기가 발생할 때 예외를 발생시키는 대신 컴파일러는 프로그램을 중지하고 대신 Solitaire 게임을 시작할 수도 있습니다. 그것은 또한 "정의되지 않은 행동"의 우산에 속합니다.
- 원칙적으로 컴파일러는 0으로 나누기가 발생할 때마다 컴퓨터를 폭발시키는 코드를 발행 할 수도 있습니다. C ++ 표준에는이를 금지하는 것이 없습니다. (미사일 비행 컨트롤러와 같은 특정 종류의 응용 프로그램에서는 바람직한 안전 기능으로 간주 될 수도 있습니다!)
- 또한 표준 은 정의되지 않은 동작을 "시간 여행"에 명시 적으로 허용 하므로 컴파일러는 0으로 나누기가 발생 하기 전에 위의 작업 (또는 다른 작업)을 수행 할 수도 있습니다 . 기본적으로 표준은 컴파일러가 프로그램의 관찰 가능한 동작이 변경되지 않는 한 자유롭게 작업 순서를 변경할 수 있도록합니다. 그러나 프로그램을 실행하면 정의되지 않은 동작이 발생하면 마지막 요구 사항도 명시 적으로 포기됩니다. 따라서 실제로 어떤 시점에서 정의되지 않은 동작을 트리거하는 모든 프로그램 실행 의 전체 동작은 정의되지 않습니다!
- 위의 결과로 컴파일러는 정의되지 않은 동작이 발생하지 않는다고 가정 할 수도 있습니다 . 일부 입력에 대해 정의되지 않은 방식으로 동작하는 프로그램에 대해 허용되는 동작 중 하나 는 입력이 무언가 있었던 것처럼 동작 하는 것입니다. 그렇지 않으면 . 즉,의 원래 값이
d
컴파일 타임에 알려지지 않았더라도 컴파일러는 여전히 값이 0 이 아니라고 가정하고 그에 따라 코드를 최적화 할 수 있습니다. OP 코드의 특정 경우에, 이것은 단지를 가정 할 때 컴파일러와 효과적으로 구별 할 수0 / 0 == 1
없지만, 예를 들어 컴파일러는puts()
inif (d == 0) puts("About to divide by zero!"); d /= d;
이 실행되지 않는다고 가정 할 수도 있습니다 !
정수를 0으로 나누는 동작은 C ++ 표준에서 정의되지 않습니다. 예외를 발생시킬 필요 는 없습니다 .
(부동 소수점을 0으로 나누는 것도 정의되지 않지만 IEEE754가 정의합니다.)
당신의 컴파일러는 최적화 d /= d
하고 있습니다. d = 1
이것은 합리적인 선택입니다. 코드에 정의되지 않은 동작이 없다고 가정 할 수 있기 때문에이 최적화를 수행 d
할 수 있습니다. 이는 0 일 수 없습니다.
부스트 세이프 숫자를 사용하여 코드에서이 경우 (및 기타 경우) C ++ 예외를 생성 할 수 있습니다. https://github.com/boostorg/safe_numerics
'developer tip' 카테고리의 다른 글
.NET DLL에 git 커밋 해시 포함 (0) | 2020.10.07 |
---|---|
ES6로 두 개체 병합 (0) | 2020.10.07 |
유니 코드를 사용한 Python 및 정규식 (0) | 2020.10.07 |
HTML, CSS 웹 페이지 만 Tomcat에 배포 (0) | 2020.10.07 |
목록에있는 튜플의 값에 액세스 (0) | 2020.10.07 |