Search
Duplicate
🥵

int의 오버플로우가 위험한 이유

간단소개
오버플로우에 의존했을 때 엉뚱한 결과가 나오는 예시까지!
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
C
C++
Scrap
태그
undefined behavior
9 more properties

unsigned int의 오버플로우

C’s unsigned integer types are ‘‘modulo’’ in the LIA−1 sense in that overflows or out-of-bounds results silently wrap. - C99 스펙
unsigned int는 오버플로우가 없습니다.
표현 가능한 개수로 나눈 나머지가 된다고 정의되어 있습니다.
#include <stdio.h> int main(void) { unsigned int num1; unsigned int num2; const char *result; scanf("%d %d", &num1, &num2); result = "!(%u > %u && %u > %u)"; if (num1 > num2 && num1 + 1 > num2) result = "%u > %u && %u > %u"; printf(result, num1, num2, num1 + 1, num2); return (0); }
C
복사
입력으로 4294967295 0를 넣으면 !(4294967295 > 0 && 0 > 0)가 되는 것을 볼 수 있습니다.
-O3 플래그로 컴파일러 최적화를 활성화해도 마찬가지입니다. unsigned int는 원래 이렇게 동작합니다.

signed int의 오버플로우

C/C++에서 signed int의 오버플로우는 정의되지 않았습니다.
왜 아직도 정의되지 않았는지 의아할 수 있는데 컴파일러 최적화 때문입니다.
수학적으로 볼 때 A가 B보다 크다면, A + 1도 당연히 B보다 클 것입니다.
이 점을 이용해 컴파일러가 최적화를 할 수도, 안 할 수도 있습니다.
#include <stdio.h> int main(void) { int num1; int num2; const char *result; scanf("%d %d", &num1, &num2); result = "!(%d > %d && %d > %d)"; if (num1 > num2 && num1 + 1 > num2) result = "%d > %d && %d > %d"; printf(result, num1, num2, num1 + 1, num2); return (0); }
C
복사
문제가 없을 수도 있습니다. 일단 여기서는 -O3 플래그로 최적화를 활성화 해 보겠습니다.
2147483647 0를 입력하면 2147483647 > 0 && -2147483648 > 0가 출력됩니다.
(num1 + 1 > num2), 즉 -2147483648 > 0true라는 뜻이죠.
하지만 컴파일러는 이 식을 (num1 > num2)으로 최적화할 수 있습니다.

undefined behavior의 위험성?

undefined behavior는 말 그대로 정의되지 않은 동작이지 반드시 다르게 동작하는 것이 아닙니다.
어떻게 동작할 것이라고도 기대해서는 안 됩니다.
어떤 결과가 나올지 모르기 때문에, undefined behavior에 의존하면 안 됩니다.
printf(”%s”, NULL)은 대부분 (null)을 출력하지만 C 표준에서는 이에 대해 정의하지 않습니다.
glibc의 경우에는 문서에 printf(”%s”, NULL)(null)을 출력한다는 내용이 있습니다.
glibc처럼 정의된 경우가 아니라면 printf(”%s”, NULL)는 undefined behavior입니다.
printf(”%s”, NULL)가 오류를 내지 않을 것이라고 기대해서는 안 됩니다.
실제로는 오류가 날 수 있고, 오류가 나도 그 printf는 잘못한 것이 없습니다.