이것은 UB입니다. ISO C ++ 용어에서 전체 프로그램의 전체 동작은 실행에 대해 완전히 지정되지 않습니다. 결국 UB에 도달 않습니다. 고전적인 예는 C ++ 표준이 관리하는 한 악마가 코에서 날아갈 수 있도록합니다. (비강 악마가 실제로 가능한 구현을 사용하지 않는 것이 좋습니다). 자세한 내용은 다른 답변을 참조하십시오.
컴파일러는 실행 경로에 대해 컴파일 타임에 "문제를 일으켜"컴파일 타임에 보이는 UB로 연결되는 것을 볼 수 있습니다.
모든 C 프로그래머가 정의되지 않은 동작에 대해 알아야 할 사항 (LLVM 블로그) 도 참조하십시오 . 거기에 설명 된 것처럼 부호가있는 UB는 컴파일러가 for(... i <= n ...)루프가 무한 루프가 아님을 증명할 수있게합니다.n 있습니다. 또한 부호 확장을 다시 실행하는 대신 int 루프 카운터를 포인터 너비로 "승격"할 수 있습니다. (따라서 UB의 결과는 서명 된 줄 바꿈을 기대하는 경우 배열의 낮은 64k 또는 4G 요소 외부에 액세스 할 수 있습니다i 는 값 범위로 .)
경우에 따라 컴파일러는 x86과 같은 잘못된 명령을 ud2실행하여 UB를 발생시키는 블록에 대해 명령 을 내릴 수 있습니다. (함수가 호출 되지 않을 수도 있으므로 컴파일러는 일반적으로 맹렬한 영향을 받아 다른 기능을 중단하거나 UB에 도달하지 않는 함수를 통해 경로를 만들 수 없습니다. 즉, 컴파일하는 기계어 코드는 여전히 작동해야합니다 UB로 연결되지 않는 모든 입력)
아마도 가장 효율적인 해결책은 불필요한 반복을 수동으로 제거하여 불필요한 factor*=10것을 피하는 것입니다.
int result = 0;
int factor = 1;
for (... i < n-1) { // stop 1 iteration early
result = ...
factor *= 10;
}
result = ... // another copy of the loop body, using the last factor
// factor *= 10; // and optimize away this dead operation.
return result;
또는 루프 본문이 큰 경우에 대해 부호없는 유형을 사용하는 것을 고려하십시오 factor. 그런 다음 부호없는 곱하기 오버플로 할 수 있으며 2의 거듭 제곱 (부호없는 유형의 값 비트 수)으로 잘 정의 된 줄 바꿈을 수행합니다.
이것은 당신이 그것을 사용하는 경우에도 괜찮 와 함께 당신의 unsigned-> 서명 변환이 넘치는 결코 특히, 서명 유형.
부호없는 부호와 2의 보수 부호 사이의 변환은 자유입니다 (모든 값에 대해 동일한 비트 패턴). C ++ 표준에 의해 지정된 int-> unsigned에 대한 모듈로 랩핑은 보수 또는 부호 / 크기와 달리 동일한 비트 패턴을 사용하여 단순화합니다.
unsigned-> signed는 비슷하지만 사소한 것이지만보다 큰 값에 대해서는 구현 정의되어 있습니다 INT_MAX. 마지막 반복에서 서명되지 않은 거대한 결과를 사용 하지 않으면 걱정할 것이 없습니다. 그러나 그렇다면 서명되지 않은 상태에서 서명되지 않은 상태로의 변환이 있습니까?를 참조하십시오 . . 값-나던 맞는 경우는 구현 정의 , 구현이 선택해야한다는 것을 의미 일부 동작; 제정신은 부호없는 비트 패턴을 자르고 (필요한 경우) 부호없는 것으로 사용합니다. 추가 작업없이 범위 내 값에 대해 같은 방식으로 작동하기 때문입니다. 그리고 그것은 확실히 UB가 아닙니다. 따라서 부호없는 큰 값은 부호없는 정수가 될 수 있습니다. 예를 들어, 후int x = u; gcc와 clang이 최적화되지 않은x>=0-fwrapv그들이 행동을 정의했기 때문에 항상없이 진실한 것처럼 .