Step by step

한 걸음 한 걸음 천천히

Programming Language/C Language

자료형과 오버플로우

개발자 까마귀 2024. 4. 27. 19:24
728x90

자료형은 데이터의 종류를 말한다.

 

자료형은 크게 세 가지 분류로 나누어 볼 수 있다.

  1. 정수형
  2. 부동소수점(실수)형
  3. 문자형

정수형에는 short > int >= long >= long long 이 있다.

short은 2Byte, int는 4Byte, long은 4~8Byte, long long은 8Byte이다.

sizeof

C언어에서 자료형이 차지하고 있는 메모리 공간을 확인하기 위해서 sizeof 연산자를 사용할 수 있다.

int n;
sizeof n; // 4
// 변수의 경우 괄호가 필요 없음
sizeof(char); // 1
sizeof(long) // 환경마다 다르지만 보통 4
sizeof(long long) // 8
sizeof(short) // 2
sizeof(int) // 4
sizeof(float) // 4
sizeof(double) // 8
sizeof(long double) // 16

단위는 Byte이다.

자료형의 범위

각 자료형이 표현할 수 있는 범위는 정해져있다.

정수 자료형

  10진수 최소 값 10진수 최대 값 16진수 최소 값 16진수 최대 값
short -32,768 32,767 8000 7FFF
int -2,147,483,648 2,147,483,647 8000 0000 7FFF FFFF
long long -9,223,372,036,854,775,808 9,223,372,036,854,775,807 8000 0000 0000 0000 7FFF FFFF FFFF FFFF
printf("%hd ~ %hd\n", 0x8000, 0x7FFF); // short
printf("%d ~ %d\n", 0x80000000, 0x7FFFFFFFF); // int
printf("%lld ~ %lld\n",
        0x8000000000000000,
               0x7FFFFFFFFFFFFFFF); // long long

MSB와 LSB

부호 값을 구분하는 방법은 MSB를 부호비트로 보느냐 아니느냐에 달려있다.

Most Significant Bit의 약자이다.

직역하면 가장 중요한 비트인데, 가장 높은 비트. 최상위 비트를 말한다.

이의 반대 용어인 LSB(Least Significant Bit)는 가장 최하위 비트를 말한다.

1 2^3 MSB
1 2^2  
0 2^1  
1 2^0 LSB

무부호

unsigned: 양수만 나타낸다.

signed: 음수도 나타낸다. 흔히 생략하여 사용한다.

  10진수 최소 값 10진수 최대 값 16진수 최소 값 16진수 최대 값
unsigned short 0 65,535 0 FFFF
unsigned int 0 4,294,967,295 0 FFFF FFFF
unsigned long long 0 18,446,744,073,709,551,615 0 FFFF FFFF FFFF FFFF
printf("%hu\n", 0x8000, 0x7FFF); // unsigned short
printf("%u\n", 0x80000000, 0x7FFFFFFFF); // unsigned int
printf("%llu\n",
        0x8000000000000000,
               0x7FFFFFFFFFFFFFFF); // unsigned long long

limit.h

위와 같이 복잡하게 출력할 필요 없이, limit.h를 통해 최대, 최소값을 출력할 수 있다.

#include <stdio.h>
#include <limits.h>

int main() {
    printf("%hd ~ %hd\n", SHRT_MIN, SHRT_MAX);
    printf("%d ~ %d\n", INT_MIN, INT_MAX);
    printf("%lld ~ %lld\n", LLONG_MIN, LLONG_MAX);
    // signed
    printf("%hu\n", USHRT_MAX);
    printf("%u\n", UINT_MAX);
    printf("%llu\n", ULLONG_MAX);
    // unsigned
    return 0;
}

부호

부호 정수는 MSB를 부호비트로 보는 것을 말한다.

컴퓨터 과학에서 음수를 표현하기 위해서 다양한 노력이 있었다.

- 1의 보수: 모든 비트를 0은 1로 1은 0으로 바꾸는 것이다.(not 연산)

- 2의 보수: 1의 보수를 한 수에 1을 더하는 것

 

1의 보수로 음수를 표현하니 -0과 +0이 존재하여 수의 낭비가 생겨 2의 보수를 사용하게 되었다.

8진수 16진수

C언어에선 8진법과 16진법을 입력 및 출력을 할 수 있다.

scanf("%d %o %x %X", &d, &o, &x, &X);
// 차례로 10, 8, 16소, 16대문자이다.
printf("%d %o %x %X", d, o, x, X);
// 출력도 같다.

// 상수로서 2, 8, 16진수
printf("%d %d %d", 0b1010, 012, 0xA);

/* 10 <--> 8
    8 <--> 16
    2  --> 8
    2  --> 16
    2  --> 10
    위와 같은 식으로 변환이 가능하다.
*/

엄밀히 따지면 0XA가 옳은 표현이지만, 편의상 소문자 x를 사용.

부동 소수점

부동 소수점 자료형의 경우 정수 자료형보다 훨씬 더 복잡한 구조를 갖는다.

상당히 어려운 개념이니 그냥 이런게 있구나 정도 하고 넘어가면 됨.

 

현재의 부동소수점수(Floating Point Number)는 IEEE(Institute of Electrical and Electronics Engineers)의 floating porint fomat을 사용하고 있다.

 

실수자료형은 3부분으로 나누어져있다.

  1. S: Sign(부호)
    0 or 양수 = 0, 음수 = 1
  2. E: Exponent(지수)
  3. M: Mantissa(가수)
    정규화 이후의 소수점 이하 자리 표현
    더보기
    정규화란 가수의 첫번째 자리가 밑수보다 작은 한자리 자연수로 바꾸는 것
lsingle-precision(단일 정밀도): 4Byte(32bits) – S(1), E(8), M(23)
  • E: bias 127 표현. 3.4 * 10 ^ 2 = 129, 3.4 * 10 ^ (-2) = 125
    127을 기준으로 +와 -를 해가며 지수를 표현한다. 

l double-precision(두배 정밀도): 8Byte(64bits) – S(1), E(11), M(52)

  • E: bias 1023 표현
    아까와 같이 설명하면, 10 ^ 2는 1025, 10 ^ (-2)는 1021

 

물론 위 해석 방법이 모든 방법에서 사용할 수 있는 것은 아니다.

문자

ASCII 문자

  • 1문자를 1B로 표현(7bit 사용). MSB는 0. 범위 = 0 ~ 127

KSC 5601

  • 1문자를 2B로 표현(16bit 사용). 각 바이트의 MSB는 1. 한글은 2,350, 한자 4,888 문자 포함
  • 현대 한글 완성자: 초성 19자 × 모음 21자 × 종성 27자 = 11,172

Unicode

  • 세계 모든 문자에 대한 고유한 코드값 부여
  • 유니코드 표현 방식(인코딩 방법): UTF(Unicode Transformation Format)
  • UTF-8: 1문자를 1B~4B
  • UTF-16: 1문자를 2/4B
  • UTF-32: 1문자를 4B

오버플로우

변수가 나타낼 수 있는 범위를 초과하는 것을 오버플로우라고 한다.

정수 오버플로우

상황에서의 오버플로우에 대해서는 직접 프로그램을 작성하여 알아보는 것이 이해가 쉽다.

int max = 0x7FFFFFFF;

printf("%d\n", max); // 2,147,483,647

max++;

printf("%d", max); // -2,147,483,648

16진수7FFF FFFF에 1을 더하게 되면 8000 0000가 되는데 이는 int 범위에서 가장 작은 값이 된다.

 

최소값에서 1을 빼줄 경우에 최대값이 되는 것 또한 오버플로우라고 한다.

무부호 정수의 오버플로우는 0에서 1을 빼는 상황(4,294,967,295이 됨), 최대값에서 1을 더하는 상황(0이 됨)

  • 0의 경우 모든 비트가 0인 상황에서 -1을 할 경우 모든 비트가 1로 바뀜
  • 최대값인 경우엔 FFFF FFFF에서 1을 더할 경우 그 다음 비트가 1 FFFF FFFF가 되는데, 앞 1은 int의 크기를 초과하기에 오버플로우가 발생하는 것

실수 오버플로우 - 언더플로우

float x = 1e39;
printf("%e", x); // inf

수가 너무 커서 발생하는 오버플로우이다.

float x = 1e-46f;
printf("%e", x); // 0.000000e+00

수가 너무 작아서 발생하는 언더플로우이다.

 

실수 상황에서의 계산에선 거의 항상 오차가 있다.

printf("%f\n", 0.1f); // 0.100000
printf("%.20f", 0.1f); // 0.10000000149011611938

 

IEEE 754문자의 Floating Point format에서는 거의 대부분의 소수를 정확하게 계산하지 못한다.

정확한 값을 계산할 수 있는 것은 2의 제곱의 역수이다. 1/2, 1/4, 1/8 · · ·

#include <stdio.h>

int main() {
    double x;
    x = (1e20 + 1) - 1e20;
    printf("%f\n",x);
    return 0;
}

1e20은 매우 작은 숫자인데, 1은 그에 비해 굉장히 큰 수이다.

이런 경우 매우 작은 수인 1e20에 의해 1이라는 숫자는 무시된다.

문자 자료형

 

문자 자료형은 char로 선언된다.

char c = 'A'; // 작은 따옴표로 문자 저장
char ch = 65; // 아스키코드로 문자 저장

printf("%c\n", ch); // 아스키코드 65인 문자 출력
printf("%d", c); // 'A' 문자의 아스키코드 출력

문자 자료형에는 정수로 변환되어 저장되기에 정수도 대입 연산이 가능하다.

더보기
아스키코드 표

제어 문자

출력 목적이 아닌 제어 목적으로 사용되는 문자이다. 아스키코드 번호를 직접 사용할 수도 있고, 이스케이프 시퀀스(\)를 사용할 수도 있다.

더보기
이스케이프 시퀀스 표

특수한 기능을 가진 문자 앞에 역슬래시(\)를 위치시키면 기능이 사라지고 문자 그 자체만 남는다.

728x90

'Programming Language > C Language' 카테고리의 다른 글

조건문  (1) 2024.04.28
연산자  (1) 2024.04.28
라이브러리 함수  (2) 2024.04.27
수식과 연산  (1) 2024.04.27
변수의 대입 연산과 초기화  (0) 2024.04.27