C & C++/디딤돌 C언어

Part 6. 정수 형식의 표현 범위와 Overflow 값 잘림 현상

언휴 2024. 1. 9. 08:51

 

[C언어]  Part 6. 정수 형식의 표현 범위와 Overflow 값 잘림 현상

17. 정수 형식의 표현 범위

char 형식과 unsigned char 형식은 정수를 표현할 때도 사용할 수 있다고 했어요.
두 가지 형식 모두 1바이트를 할당하여 256가지의 정수를 표현할 수 있답니다.

 

unsigned char 형식은 부호 없는 정수만 표현하므로 0~0xFF(0~255)까지 표현 가능해요.

char 형식은 최상위 비트가 0인 0x00~0x7F(0~127)까지는 부호없는 정수예요.
그리고 최상위 비트가 1인 0x80~0xFF(-128~-1)까지는 부호있는 정수죠.

 

◈ char 형식과 unsigned char 형식의 표현 범위 확인

#include <stdio.h>
int main()
{
    char c = 0;
    unsigned char uc = 0;    
    c = 0x7F; //최상위 비트가 0
    uc = 0x7F;    
    printf("%d %d\n",c,uc);
    c = 0x80; //최상위 비트가 1
    uc = 0x80;
    printf("%d %d\n",c,uc);
    c = 0xFF;
    uc=0xFF;
    printf("%d %d\n",c,uc);
    return 0;
}

◈ 실행 결과

127 127
-128 128
-1 255

다음은 부호 있는 정수를 표현하는 char, short, int, long 형식으로 표현할 수 있는 최대값과 최소값을 확인하는 코드예요.

 

◈ 부호 있는 정수 형식의 최솟값과 최댓값

#include <stdio.h>
int main()
{
    char c = 0x7F;
    short s = 0x7FFF;
    int i = 0x7FFFFFFF;
    long l = 0x7FFFFFFF;
    long long ll = 0x7FFFFFFFFFFFFFFFLL;
    
    printf("char max:%d ",c); 
    c = 0x80;
    printf("char min:%d \n",c); 
 
    printf("short max:%d ",s); 
    s = 0x8000;
    printf("short min:%d \n",s); 
 
    printf("int max:%d ",i); 
    i = 0x80000000;
    printf("int min:%d \n",i); 
 
    printf("long max:%d ",l); 
    l = 0x80000000;
    printf("long min:%d \n",l);    
 
    printf("long long max:%lld ",ll); 
    ll = 0x8000000000000000;
    printf("long long min:%lld \n",ll); 
    return 0;
}

◈ 실행 결과


char max:127 char min:-128
short max:32767 short min:-32768
int max:2147483647 int min:-2147483648
long max:2147483647 long min:-2147483648
long long max: 9223372036854775807 long long min: -9223372036854775808

 

여기서 잠깐!
설마 눈으로만 보고 머리로 이해할 수 있다고 개발 도구에서 직접 확인하지 않는 것은 아니죠?
프로그램 언어는 개발 도구를 통해 몸으로 익혀야 합니다.
코드를 보면서 작성해도 오타가 나오거든요.
오류를 확인하면서 문제를 해결하는 것을 익히는 것은 매우 중요해요.

18. OVERFLOW와 값 잘림 현상

만약 정수 형식에서 표현할 수 있는 범위를 벗어나는 연산을 수행하면 어떻게 될까요?

 

표현 범위를 벗어날 때 처리하는 방식은 프로그래밍 언어마다 달라요.
C언어에서는 표현 범위를 벗어나도 프로그램은 예외를 발생하지 않고 동작해요.
물론 연산 결과는 개발자가 원하는 결과가 아닌 엉뚱한 값이 되겠죠.
이처럼 연산 결과가 표현 범위의 벗어나는 것을 오버플로우(overflow)라고 불러요.
좀 더 세분화하면 최대값을 넘어서는 것을 오버플로우, 최소값보다 작아지는 것을 언더플로우(underflow)라고 부르죠.

 

예를 들어 char 형식 변수 c1에 127(16진수 0x7F)로 설정한 후에 1을 더하면 오버플로우가 발생해요.
이 때 연산 결과는 -128(16진수 0x80)이예요.
물론 c1의 값이 -128(16진수 0x80)일 때 1을 빼면 127(16진수 0x7F)이구요.

 

◈ 오버플로우와 언더플로우

#include <stdio.h>
int main()
{
    char c = 127;        //char 형식 변수 c를 선언하고 127(0x7F)로 초기화
    c = c+1;
    printf("c: %d \n",c); //변수 c의 값 출력
    c = c-1;
    printf("c:%d \n",c);  //변수 c의 값 출력
    return 0;
}

◈ 실행 결과

c: -128
c:127

 

C언어에서는 표현 범위가 다른 정수 형식 사이에 묵시적 형변환을 제공하죠.
표현 범위가 좁은 형식 변수를 넓은 형식 변수에 대입하는 것은 아무런 문제도 발생하지 않아요.
그런데 표현 범위가 넓은 형식 변수를 좁은 형식 변수에 대입할 때는 주의하세요.

 

예를 들어 int 형식 변수 i에 0x1234 값이 있을 때 char 형식 변수 c에 대입하면 하위 1바이트의 값인 0x34만 남아요.
이러한 현상을 값 잘림 현상이라고 불러요.

 

◈ 정수 값 잘림 현상

#include <stdio.h>
int main()
{
    int i = 0x1234;
    char c=0;
 
    c = i;
    printf("c:%#x i:%#x \n",c,i); //16진수로 출력
    return 0;
}

◈ 실행 결과

c:0x34 i:0x1234

◈ 기본 연습
1. short 형식의 변수 s를 0x7FFF 값으로 초기화한 후 s 변수에 1을 더하면 10진수로 얼마인지 확인하는 코드를 작성하시오.
그리고 실행한 후 출력 결과의 이유를 설명하시오.

//1. short 형식의 변수 s를 0x7FFF 값으로 초기화
//s 변수에 1을 더하면 10진수로 얼마인지 확인하는 코드를 작성하시오.
//그리고 실행한 후 출력 결과의 이유를 설명하시오.
 
#include <stdio.h>
int main(void)
{
    short s = 0x7FFF;
 
    printf("short s: %d\n",s);
    s+=1;
    printf("short s: %d\n",s);
    
    return 0;
}

▷ 실행 결과

short s: 32767
short s: -32768

▷ 이유
short  형식의 크기는 2바이트이며 부호있는 정수를 표현하는 형식입니다.
0x7FFF는 이진수로 0111 1111 1111 1111 이며 short로 표현할 수 있는 가장 큰 정수입니다.
여기에 1을 더하면 이진수로 1000 0000 0000 0000 이며 short로 표현할 수 있는 가장 작은 정수입니다.
이러한 현상을 overflow라고 부릅니다.

 

2. int 형식 변수 i를 128 값으로 초기화한 후 char 형식 변수 c에 i를 대입한 후에 값을 출력하는 코드를 작성하시오.
그리고 실행한 후 출력 결과의 이유를 설명하시오.

//2. int 형식 변수 i를 128 값으로 초기화한 후 
// char 형식 변수 c에 i를 대입한 후에 값을 출력하는 코드를 작성하시오. 
// 그리고 실행한 후 출력 결과의 이유를 설명하시오.

#include <stdio.h>
int main(void)
{
    int i = 128;
    char c;
    c = i;

    printf("c: %d\n",c);
    return 0;
}

▷ 실행 결과

-128

 

▷ 이유
int 형식 128은 이진수로 0000 0000 0000 0000 0000 0000 1000 0000 입니다.
char 형식의 크기는 1바이트입니다.
char 형식 변수에 int 형식을 대입하면 하위 1바이트를 제외한 나머지는 값이 잘립니다.
따라서 대입 연산으로 c 의 메모리에는 1000 0000 을 설정합니다.
2진 보수 방식에서 1000 0000은 -128입니다.