가장 큰 대답은 잘못된 (그러나 일반적인) 오해입니다.
정의되지 않은 동작은 런타임 속성입니다 *. 그것은 "시간 여행"할 수 없습니다 !
특정 작업은 표준에 의해 정의되어 부작용이 있으며 최적화 할 수 없습니다. I / O를 수행하거나 volatile
변수 에 액세스하는 작업 이이 범주에 속합니다.
그러나 주의 할 점이 있습니다. UB는 이전 작업 을 취소 하는 동작을 포함하여 모든 동작 이 될 수 있습니다 . 이는 경우에 따라 이전 코드를 최적화하는 것과 유사한 결과를 가져올 수 있습니다.
사실, 이것은 최상위 답변의 인용문과 일치합니다 (강조 표시).
잘 구성된 프로그램을 실행하는 준수 구현은 동일한 프로그램 및 동일한 입력을 사용하여 추상 기계의 해당 인스턴스의 가능한 실행 중 하나와 동일한 관찰 가능한 동작을 생성해야합니다.
그러나 이러한 실행에 정의되지 않은 작업이 포함되어있는 경우이 국제 표준 은 해당 입력으로 해당 프로그램을 실행 하는 구현에 대한 요구 사항을 지정 하지 않습니다 (첫 번째 정의되지 않은 작업 이전의 작업에 대해서도).
예,이 인용문 은 "정의되지 않은 첫 번째 작업 이전의 작업에 대해서도" 라고 말하지만 , 이것은 단순히 컴파일 된 것이 아니라 실행 중인 코드에 대한 것임을 주목하십시오 .
결국 실제로 도달하지 않은 정의되지 않은 동작은 아무 작업도 수행하지 않으며 UB가 포함 된 행에 실제로 도달하려면 선행 코드가 먼저 실행되어야합니다!
예, UB가 실행 되면 이전 작업의 효과가 정의되지 않습니다. 그러나 그것이 일어날 때까지 프로그램의 실행은 잘 정의되어 있습니다.
그러나 이러한 일이 발생하는 프로그램의 모든 실행은 이전 작업을 수행했지만 그 효과를 취소 하는 프로그램을 포함 하여 동등한 프로그램에 최적화 될 수 있습니다 . 결과적으로 이전 코드는 그 효과가 취소되는 것과 동일 할 때마다 최적화 될 수 있습니다 . 그렇지 않으면 할 수 없습니다. 예는 아래를 참조하십시오.
* 참고 : 이것은 컴파일 타임에 발생하는 UB 와 일치 하지 않습니다 . 컴파일러가 실제로 UB 코드 가 모든 입력에 대해 항상 실행 된다는 것을 증명할 수 있다면 UB는 컴파일 시간으로 확장 할 수 있습니다. 그러나이를 위해서는 이전의 모든 코드가 결국를 반환 한다는 사실을 알아야 하며 이는 강력한 요구 사항입니다. 다시 한 번 예 / 설명은 아래를 참조하십시오.
이를 구체적으로 설명하려면 다음 코드 가 뒤에 오는 foo
정의되지 않은 동작에 관계없이 인쇄 하고 입력을 기다려야합니다.
printf("foo")
getchar()
*(char*)1 = 1
그러나 foo
UB가 발생한 후 화면에 남아 있거나 입력 한 문자가 더 이상 입력 버퍼에 없다는 보장은 없습니다 . 이 두 작업 모두 "취소"할 수 있으며 UB "시간 이동"과 유사한 효과를 갖습니다.
는 IF getchar()
라인이 아니었다는 것이다 선이 멀리 최적화 할 법적 될 경우에만 그리고 만약 그 것이다 구별 출력에서 foo
다음과 "을 취소하고".
둘을 구별 할 수 없는지 여부는 전적으로 구현 (예 : 컴파일러 및 표준 라이브러리)에 따라 다릅니다 . 예를 들어, 다른 프로그램이 출력을 읽을 때까지 기다리는 동안 여기에서 스레드를 printf
차단할 수 있습니까? 아니면 즉시 반환됩니까?
물론 컴파일러는 특정 버전의 printf
에서 허용되는 동작을 알고 있으므로 그에 따라 최적화 할 수 있으며 결과적으로 printf
다른 경우가 아닌 경우에 최적화 될 수 있습니다. 그러나 다시 말하지만, UB로 인해 이전 코드가 "중독"된 것이 아니라 이전 작업을 취소 한 UB와 구별 할 수 없다는 것이 정당 합니다.
a
(자체 계산을 제외하고) 사용되지 않는 것을 알아 내고 간단히 제거 할 수 있는지 궁금합니다a