C 표준은 컴파일러에게 최적화를 수행 할 수있는 많은 권한을 제공합니다. 초기화되지 않은 메모리가 임의의 비트 패턴으로 설정되고 모든 작업이 작성된 순서대로 수행되는 프로그램의 순진한 모델을 가정하면 이러한 최적화의 결과는 놀라 울 수 있습니다.
참고 : 다음 예제는 x
주소를 사용하지 않았기 때문에 유효하므로 "등록과 유사"합니다. 유형에 x
트랩 표현이있는 경우에도 유효합니다 . 서명되지 않은 유형의 경우는 드물며 (최소한 1 비트의 스토리지를 "낭비"해야하며 문서화해야 함) unsigned char
. x
서명 된 유형이있는 경우 구현은-(2 n-1 -1)과 2 n-1 -1 사이의 숫자가 아닌 비트 패턴을 트랩 표현으로 정의 할 수 있습니다. Jens Gustedt의 답변을 참조하십시오 .
레지스터가 메모리보다 빠르기 때문에 컴파일러는 레지스터를 변수에 할당하려고합니다. 프로그램은 프로세서에있는 레지스터보다 더 많은 변수를 사용할 수 있기 때문에 컴파일러는 레지스터 할당을 수행하여 다른 시간에 동일한 레지스터를 사용하는 다른 변수를 만듭니다. 프로그램 조각을 고려하십시오
unsigned x, y, z;
y = 0;
z = 4;
x = - x;
y = y + z;
x = y + 1;
라인 3이 평가 될 때 x
아직 초기화되지 않았으므로 (컴파일러의 이유) 라인 3은 컴파일러가 알아낼만큼 똑똑하지 않은 다른 조건으로 인해 발생할 수없는 일종의 우연이어야합니다. z
4 번 줄 이후 에는 사용 x
되지 않고 5 번 줄 이전에는 사용되지 않으므로 두 변수에 동일한 레지스터를 사용할 수 있습니다. 따라서이 작은 프로그램은 레지스터에 대한 다음 작업으로 컴파일됩니다.
r1 = 0;
r0 = 4;
r0 = - r0;
r1 += r0;
r0 = r1;
의 최종 값 x
은의 최종 값 r0
이고의 최종 값 y
은의 최종 값입니다 r1
. 이러한 값은 x = -3 및 y = -4이며 x
제대로 초기화 된 경우 발생하는 5와 4가 아닙니다 .
보다 정교한 예를 보려면 다음 코드 조각을 고려하십시오.
unsigned i, x;
for (i = 0; i < 10; i++) {
x = (condition() ? some_value() : -x);
}
컴파일러 condition
가 부작용이 없음을 감지했다고 가정합니다 . condition
수정하지 않기 때문에 x
컴파일러는 루프를 통한 첫 번째 실행 x
이 아직 초기화되지 않았으므로 액세스 할 수 없음을 알고 있습니다 . 따라서 루프 본문의 첫 번째 실행은와 동일 x = some_value()
하므로 조건을 테스트 할 필요가 없습니다. 컴파일러는 여러분이 작성한 것처럼이 코드를 컴파일 할 수 있습니다.
unsigned i, x;
i = 0;
x = some_value();
for (i = 1; i < 10; i++) {
x = (condition() ? some_value() : -x);
}
이 컴파일러의 내부 모델링 될 수있는 방법에 따라 값이 있음을 고려하는 것입니다 x
이 편리하다 어떤 값 만큼으로 x
초기화되지 않습니다. 초기화되지 않은 변수가 정의되지 않은 경우의 동작은 단순히 지정되지 않은 값을 갖는 변수가 아니라 변수이기 때문에 컴파일러는 편리한 값 간의 특별한 수학적 관계를 추적 할 필요가 없습니다. 따라서 컴파일러는 위의 코드를 다음과 같이 분석 할 수 있습니다.
- 첫 번째 루프 반복 중에는
x
시간 -x
이 평가 될 때까지 초기화되지 않습니다.
-x
정의되지 않은 동작이 있으므로 그 값은 무엇이든 편리합니다.
- 최적화 규칙이 적용 되므로이 코드를 .
condition ? value : value
condition; value
질문의 코드와 마주 쳤을 때이 동일한 컴파일러 x = - x
는 평가 될 때 의 값 -x
이 무엇이든 편리 하다는 것을 분석 합니다. 따라서 할당을 최적화 할 수 있습니다.
위에서 설명한대로 동작하는 컴파일러의 예를 찾지는 않았지만 좋은 컴파일러가 시도하는 일종의 최적화입니다. 나는 하나를 만나도 놀라지 않을 것입니다. 다음은 프로그램이 충돌하는 컴파일러의 덜 그럴듯한 예입니다. (어떤 종류의 고급 디버깅 모드에서 프로그램을 컴파일하는 것은 그다지 믿을 수없는 일이 아닙니다.)
이 가상 컴파일러는 다른 메모리 페이지의 모든 변수를 매핑하고 페이지 속성을 설정하여 초기화되지 않은 변수에서 읽는 것이 디버거를 호출하는 프로세서 트랩을 유발하도록합니다. 변수에 대한 모든 할당은 먼저 해당 메모리 페이지가 정상적으로 매핑되었는지 확인합니다. 이 컴파일러는 고급 최적화를 수행하지 않습니다. 디버깅 모드에 있으며 초기화되지 않은 변수와 같은 버그를 쉽게 찾을 수 있습니다. 시 x = - x
평가되고, 우측 트랩 발생 디버거 위로 발사.