예측할 수 없는 루프 동작을 포함하는 C 컴파일 수수께끼
다음 코드는 흥미로운 컴파일 문제를 나타냅니다.
<code class="c++">#include <iostream> #include <complex> using namespace std; int main() { complex<int> delta; complex<int> mc[4] = {0}; for(int di = 0; di < 4; di++, delta = mc[di]) { cout << di << endl; } return 0; }</code>
반대 "0, 1, 2, 3"의 예상 출력이 종료되면 코드는 "0, 1, 2, 3, 4, 5, ..."의 끝없는 반복을 생성합니다. 조사해 보면, 비교 di < 4가 제대로 작동하지 않아 무한 루프가 발생합니다.
겉으로는 무해해 보이는 할당 delta = mc[di]를 비활성화하면 문제가 마법처럼 해결되어 의도한 출력이 생성됩니다. 이 간단한 행동이 일으키는 문제는 무엇입니까?
정의되지 않은 동작 탐구
이 미스터리를 푸는 열쇠는 정의되지 않은 동작을 이해하는 데 있습니다. delta = mc[di] 할당은 루프의 마지막 반복에서 범위를 벗어난 배열에 대한 액세스를 트리거합니다. 많은 컴파일러는 최적화 전략을 기반으로 정의되지 않은 동작이 없다고 가정할 수 있지만 이 가정에는 본질적으로 결함이 있습니다.
GCC는 최적화가 활성화된 상태에서 정의되지 않은 동작이 없다고 가정하여 루프를 공격적으로 최적화할 수 있습니다. 이러한 최적화는 di < 범위를 벗어난 배열 액세스는 정의되지 않은 동작을 구성하므로 4는 항상 참입니다.
결과적으로, 조건 di < 4는 항상 충족됩니다. 이러한 잘못된 최적화를 방지하기 위해 -fno-aggressive-loop-optimizations 플래그를 GCC에 추가할 수 있습니다.
컴파일러의 내부 작동 방식 공개
최적화된 코드는 di < 4 검사가 제거되고 무조건적인 jmp 명령으로 대체됩니다. 이 동작은 정의되지 않은 동작이 없다는 가정에 부합하므로 무한 루프가 발생합니다.
이 동작과 반대로 -fsanitize=undefed인 Clang은 이 경우를 포착합니다. 그러나 동일한 플래그를 사용하는 GCC는 이 특정 인스턴스에서 경고를 발생시키지 않습니다.
정의되지 않은 동작의 위험
C 표준에 정의된 정의되지 않은 동작, 상황을 완전히 무시하는 등 예측할 수 없는 결과를 허용합니다. 정의되지 않은 동작은 컴파일러 불일치와 예상치 못한 런타임 동작으로 이어질 수 있으므로 어떤 대가를 치르더라도 피해야 합니다.
이러한 함정을 피하려면 프로그래머는 의도한 의미를 준수하는 잘 정의된 코드를 위해 노력해야 합니다. 또한 컴파일러는 정의되지 않은 잠재적인 동작을 개발자에게 경고하기 위해 적절한 방어 조치를 구현해야 합니다.
위 내용은 복잡한 변수에 값을 할당하면 C 프로그램에서 겉보기에는 무해한 동작처럼 보이지만 무한 루프가 발생하는 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!