C++의 부동소수점→정수 변환이 정의되지 않은 동작을 일으키는 경우

1 hour ago 1

float의 소수부를 버린 값이 대상 정수형 범위를 벗어나면 정의되지 않은 동작(UB) 이 발생하며, 암시적 변환·함수형 캐스트·static_cast 모두 영향받음 -Wall과 -Wextra는 이를 경고하지 않고, -Wconversion도 암시적 변환만 탐지해 놓치기 쉬움 Microsoft GSL의 안전한 축소 변환 함수 gsl::narrow도 일부 부동소수점→정수 입력에서 UB를 일으켜, 표현할 수 없는 값에 예외를 던진다는 문서의 동작을 지키지 못함 x86의 CVTTSS2SI는 표현 불가능한 값을 INT_MIN으로 처리하지만, AArch64의 FCVTZS는 포화 변환하고 NaN을 0으로 바꾸므로 하드웨어별 결과가 달라질 수 있음 안전하게 변환하려면 캐스트 전에 범위를 검사해야 하며, Clang·GCC의 UBSan 옵션 -fsanitize=float-cast-overflow로 문제를 탐지할 수 있음 변환 규칙과 탐지의 한계 C++ 부동소수점-정수 변환 규칙에 따르면, 소수부를 버린 뒤 값이 대상 정수형에 들어가지 않으면 정의되지 않은 동작이 됨 대상이 unsigned여도 모듈러 산술은 적용되지 않음 int i0 = f, int(f), static_cast<int>(f) 모두 일부 입력에서 UB를 일으킴 일반적인 컴파일러 경고만으로는 문제를 모두 찾기 어려움 -Wall과 -Wextra는 세 변환 모두 경고하지 않음 -Wconversion은 암시적 변환만 경고함 현재 프로세서와 컴파일러에서 프로그램이 계속 실행되더라도 결과는 플랫폼마다 달라질 수 있음 x86의 CVTTSS2SI는 표현할 수 없는 입력을 INT_MIN으로 매핑함 AArch64의 FCVTZS는 포화 처리하고 NaN을 0으로 매핑함 실행된 UB는 컴파일러가 다른 변환을 적용할 때 코드가 갑자기 오작동하는 원인이 될 수 있음 GSL 사례와 안전한 대응 Microsoft Guidelines Support Library의 gsl::narrow는 대상 형식으로 표현할 수 없는 값에 예외를 던지는 안전한 축소 변환을 표방함 실제 부동소수점→정수 변환은 일부 입력에서 먼저 UB를 실행하므로 문서와 일치하지 않음 GSL 측은 대상 플랫폼에서 하드웨어 트랩 표현을 건드리지 않아 내부 UB가 무해하다고 판단했으며, 이 논리가 코드에 반영된 채 문제는 수정되지 않음 올바른 해결책은 캐스트 전에 범위를 검사하는 것임 Rust의 포화 변환 방식을 바탕으로 한 c...

Read Entire Article