[C++] 자료형(Data Type) - 정수형, 실수형

2024. 2. 26. 14:32Programming Language/C++

아래 링크 클릭 시 해당 본문으로 이동

자료형(Data Type)


자료형 (Data Type)

• 변수가 어떤 자료의 형태로 나타나는지 알려주는 역할을 하며, 타입(type) 또는 데이터 타입이라고도 표현한다.

▷ 예시

int i = 0;
// int → 자료형
// i → 변수이자 객체이다.

객체(Instance) : 내가 의도한 자료형의 실질적인 데이터

실체가 없던 자료형 `int`를 실제로 만들어낸 `i`가 바로 객체이다.

  ex) 도장 = 자료형, 도장으로 찍어낸 것 = 객체


자료형 종류

• 무치형, 논리형, 정수형, 실수형

자료형 크기 (byte) 범위
무치형(Void Data Types) : 타입이 없을 때 사용한다.
무치형 void - -
논리형 : 논리적인 값(true / false)을 나타낸다.
논리형 bool 1 0 ~ 1
(signed) char, unsigned char → 문자형이지만 표현 방식이 정수형이다.
문자형 (signed) char 1 -128 ~ 127
unsigned char 1 0 ~ 255
wchar_t 2 0 ~ 65,535
정수형 (signed) short 2 -32,768 ~ 32,767
➜ 약 -3만 ~ 3만
(signed) short int
unsigned short (int) 2 0 ~ 65,535
➜ 0 ~ 약 6만
(signed) int 4 -2,147,483,648 ~ 2,147,783,647
➜ 약 -21억 ~ 21억
unsigned int 4 0 ~ 4,276,967,295
➜ 0 ~ 42억
(signed) long 4 -2,147,483,648 ~ 2,147,783,647
➜ 약 -21억 ~ 21억
(signed) long int
unsigned long (int) 4 0 ~ 4,276,967,295
➜ 0 ~ 42억
(signed) long long 8 -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
(signed) long long int
 
실수형 float 4 ±3.4 × 10^(-37) ~ ±3.4 × 10^38 (7개의 자릿수)
double 8 ±1.7 × 10^(-307) ~ ±1.7 × 10^308 (15개의 자릿수)
long double

float vs. double

실수를 상수로 표현할 때 소수점 뒤 `f`의 유무에 따라 자료형이 달라진다.

• 상수 : 변하지 않는 수

• `f`를 붙이면 ➜ `float`

• `f`를 붙이지 않으면 ➜ `double`

data = 10.f / 3.f;  // float
data = 10. / 3.  // double

특별한 이유가 아니라면 같은 type끼리 연산하는 것이 좋다.

서로 다른 type끼리 연산하는 경우 컴파일러가 자동으로 변환해주긴 하지만, 타입 캐스팅으로 타입을 변환해 주는 것이 좋다.

타입 캐스팅(type casting, 형변환) : 변환할 대상(데이터) 앞에 명시적으로 `(자료형)`을 붙여서 타입을 변환해 주는 것

▷ 예시

// float형과 int형의 연산 결과를 float형 변수에 넣어야 되므로 int형인 30을 float으로 타입 캐스팅했다.
float b = 11.1234f + (float)30;

bit

• 메모리에 데이터를 저장할 때 쓰인다.

0 1을 표현하는 최소 단위로, 더 이상 쪼갤 수 없다.

1byte = 8bit

  ex) int : 4byte = 32bit

• KB, MB, GB, TB
  ◦ 2^10 = 1024byte = 1KB
  ◦ 1024KB = 1MB
  ◦ 1024MB = 1GB
  ◦ 1024GB = 1TB (= 2^40byte)

8bit(1byte)로 표현할 수 있는 경우의 수(가지 수) = 256가지

2가지
(0 또는 1)
2가지 2가지 2가지 2가지 2가지 2가지 2가지

한 bit당 2가지씩 8개이므로 2^8 = 256가지이다.

다른 정수형들의 경우의 수

• char(1byte) : 2^8 = 256가지

• short(2byte) : 2^8 x 2^8 = 2^16 = 65536가지 (unsigned가 아닌 그냥 short라면 범위는 대략 -3만 ~ 3만 정도이다.)

• int(4byte) : 2^32 (= 약 42억)

• long(4byte) : 2^32

• long long(8byte) : 2^64

더보기

 char
문자라는 뜻인 character의 약자로, 차 또는 캐릭터라고 읽는다.

나는 character의 약자이기 때문에 캐릭터라고 읽는다.

게임 개발할 때 자료형 때문에 문제가 생기는 경우

내가 표현할 수치의 데이터가 어느 정도면 충분한지를 생각해서 자료형을 선택해야 한다.

ex) RPG 게임

더보기

A몬스터의 체력을 저장하는 int 타입의 공간이다.
몬스터가 대미지를 입거나 버프를 받으면 최대 체력을 20% 늘어나게 했다.

(몬스터 체력으로 표현할 수 있는 수는 int로 설정했기 때문에 약 -21억 ~ 21억)
처음에는 몬스터 체력이 21억을 넘을 것이라는 것을 생각하지 못했다.

(플레이어들이 공격했을 때의 대미지가 처음에는 200 ~ 300 정도 됐었는데 게임이 오랫동안 유지되면서 9000만, 10억이 되어버렸다.)
몬스터 체력이 약 21억(int)까지 늘어난 상태에서 체력 버프 20%를 받는데, 그 순간 음수가 되어버려서 갑자기 죽어버린다.
int가 32bit인데 맨 앞 bit가 1이 되면 signed에서는 음수로 인식하기 때문이다.

8bit로 표현한 값

• 각각의 bit값이 1일 때의 값

2^7
= 128
2^6
= 64
2^5
= 32
2^4
= 16
2^3
= 8
2^2
= 4
2^1
= 2
2^0
= 1

 

8bit로 0~2를 표현하면 아래와 같다.

0 0 0 0 0 0 0 0

= 0

0 0 0 0 0 0 0 1

= 2^0 = 1

0 0 0 0 0 0 1 0

= 2^1 = 2

 

우리가 평소에 사용하는 10진수와 비슷하다.

10^3 = 1000 10^2 = 100 10^1 = 10 10^0 = 1

1. 정수형 자료형

signed unsigned
• 양수, 음수 표현
• 생략 가능 (보통은 생략한다.)
• 양수만 표현

일반적으로 자료형 앞에 아무것도 붙이지 않으면 signed를 의미하는데, 컴파일러에 따라서 기본값이 unsigned일 수도 있다.

 

▷ 예시 (char)

char c1 = 0;  // signed char c1 = 0;
unsigned char c2 = 0;

`c1` ➜ 양수, 음수를 표현하는 공간이 만들어진다.

`c2` ➜ 양수만 표현하는 공간이 만들어진다.


양수만 표현할 때 (1byte)

1) 경우의 수 : 256가지

2) 표현 가능한 값 : 0~255

2가지 2가지 2가지 2가지 2가지 2가지 2가지 2가지

 

▷ 1byte 정수형 unsigned 변수에 256을 저장했을 때

unsigned char c2 = 0;
c2 = 256;  // 0'\0'
// '\0'은 숫자 0에 해당하는 ASCII 문자이다.
// char는 표현 방식은 정수형이지만 문자를 나타내는 것이 목적인 문자 자료형이므로 정수를 저장하면 문자도 같이 저장된다.

c2에 256 대입

  1 1 1 1 1 1 1 1

= 255

+1

1 0 0 0 0 0 0 0 0

= 256

 

255의 2진수에 1을 더해서 `1 0000 0000`이 나왔어도 char은 1byte(8bit)이기 때문에 맨 앞에 있는 1은 버려지므로 0이 된다.


양수, 음수 둘 다 표현할 때 (1byte)

1) 경우의 수 : 256가지

2) 표현 가능한 값 : -128~127
[-1~-128 : 128개] + [0~127 : 128개]

MSB(Most Significant Bit, 가장 중요한 비트)

최상위 비트로, 맨 앞의 첫 번째 비트트는 부호를 표시하기 위해 사용한다.

1) 맨 앞 비트 = 0 → 양수

0 2가지 2가지 2가지 2가지 2가지 2가지 2가지

표현 가능한 값 : 0 ~ 127

 

2) 맨 앞 비트 = 1 → 음수

1 2가지 2가지 2가지 2가지 2가지 2가지 2가지

표현 가능한 값 : -1 ~ -128


Q. 맨 앞 비트가 1이면 음수라고 했는데, 1을 2진수로 나타낸 `0000 0001`에서 맨 앞 bit만 1로 바꾸면 -1이 될까?

A. 결론부터 말하면 아니다.

음수 찾기 (1의 보수, 2의 보수)

※ 음수 찾는 간단한 방법

 비트를 반전시키고(1을 0으로, 0을 1로 = 1의 보수) 1을 더하면(2의 보수) 된다.

 

1의 보수는 +0(`0000 0000`)과 -0(`1111 1111`)이 존재하기 때문에 논리적으로 맞지 않다.

2의 보수에서는 +0(`0000 0000`)의 비트를 반전시키고 1을 더하면 다시 `0000 0000`이 되기 때문에 -0은 존재하지 않는다.

2의 보수는 덧셈 연산에서 발생하는 오버플로우 처리가 1의 보수 형식보다 간단하며, 컴퓨터 시스템에서 실제로 사용하는 형식이다.

• 오버플로우(overflow) : 이진 연산에서 덧셈이나 뺄셈 연산의 결과가 주어진 비트 수로 표현할 수 있는 범위를 초과하는 경우를 말한다.

1의 보수와 2의 보수로 음수 찾는 과정

▷ +1과 -1 (1byte)

1) 1의 보수

• 2진수 자릿수값이 모두 1인 수 - 변환하고자 하는 2진수

// 1의 1의 보수
  1111 1111
- 0000 0001
=============
  1111 1110

 

+1 : `0000 0001`

-1(1의 1의 보수) : `1111 1110`

 

2) 2의 보수

• `1의 보수값 + 1`

// 1의 2의 보수
  1111 1110
+         1
=============
  1111 1111

// +1 비트값과 -1 비트값을 더해서 0이 나오는지 확인
  0000 0001
+ 1111 1111
=============
  0000 0000

 +1 : `0000 0001`

 -1(1의 2의 보수) : `1111 1111`

 

여기서 알 수 있는 사실 2가지

① 1의 보수와 2의 보수의 양수 표현은 같지만 음수 표현은 다르다.

② 무조건 맨 앞 비트를 0에서 1로 바꾼다고 해서 해당 값의 음수가 되는 것은 아니다.

같은 비트여도 보는 관점에 따라서 해석이 달라진다.

1111 1111

• 양수의 관점(unsigned char) = 255

• 음수의 관점(char) = -1

컴퓨터 입장에서 `1111 1111`는 8개의 비트가 전부 1로 채워진 비트이다.

하지만 보는 관점이 양수일 때는 255으로, 음수일 때는 -1으로 해석된다.
가족을 예로 들었을 때, 내 입장에서 아빠지만 할아버지 입장에서 아빠는 아들인 것처럼 사람 자체는 달라지지 않았지만 누구의 관점이냐에 따라 다르게 해석된다.

char vs. unsigned char

// 255 대입
char c1 = 0;
c1 = 255;  // -1

unsigned char c2 = 0;
c2 = 255;  // 255
// -1 대입
char c1 = 0;
c1 = -1;  // -1

unsigned char c2 = 0;
c2 = -1;  // 255

2. 실수형 자료형

int a = 3 + 3.0;
a는 6
경고

 정수 표현 방식 ≠ 실수 표현 방식

bit 상태값 : 정수형 ≠ 실수형

  ex) 3 ≠ 3.0

정수 표현 방식은 소수점으로 표현할 수 없다.
실수 안 할 자신 있고 쓰는 의도를 정확히 파악한 것이 아니면 정수와 실수를 섞어서 쓰는 것은 지양해야 한다.

  부동 소수점 고정 소수점
설명 • 컴퓨터에서 실수를 표현할 때 소수점의 위치를 고정하지 않는 것
소수점이 움직인다고 생각하면 된다.
• 고정 소수점에 비해 표현 가능한 값의 범위가 넓다.
• 소수점이 움직이지 않고 고정되어 있는 것

ex) 12.34

고정 소수점 : 12.34

부동 소수점 : 1.234 x 10 = 0.1234 x 10^2 = 0.01234 x 10^3 = 0.001234 x 10^4 = …

위 내용의 32비트 실수는 float이다. (float : 4byte = 32bit)

 

▷ 21.8125

21의 2진수 ➜ `10101`

10진수 → 2진수 변환
변환하려는 값을 몫이 1이 되어 더 이상 나눠지지 않을 때까지 2로 나눈다.
몫인 1과 나머지 숫자(0 또는 1)를 역순으로 합치면 된다.

0.8125의 2진수 ➜ `0.1101`

 

10진법 : 0.1에서 1이 되려면 1/10이 10개 모여야 한다. (= 0.1이 10개 모여야 한다.)
2진법 : 0.1에서 1이 되려면 1/2이 2개 모여야 한다. (= 0.5가 2개 모여야 한다.)
0.1 x 10개(진수) = 0.5 x 2개(진수) = 1로 생각하기

소수점 아래 값 - 10진수 vs. 2진수

1) 10진수

소수점 (10진수) 음수 지수
0.1 10^(-1)
0.01 10^(-2)
0.001 10^(-3)
0.0001 10^(-4)

 

2) 2진수

10진수와 달리 아래 표의 `0.0001` ~ `0.1`은 비트를 뜻한다.

비트 (2진수) 음수 지수 (10진수) 소수점 (10진수)
`0.1` 2^-1 0.5
`0.01` 2^-2 0.25
`0.001` 2^-3 0.125
`0.0001` 2^-4 0.625

 

2진수 `0.1101`이 0.8125인지 확인 ➜ 0.5 + 0.25 + 0 + 0.625 = 0.8125

정규화

• 소수점을 맨 앞으로 보내고 2의 n제곱을 곱해준다.

10진법에서 소수점을 맨 앞으로 보내고 10의 n제곱을 곱한 것처럼 2진법도 같은 방식이다.

ex) 10진수 : 10000 = 0.1 x 10^5  /  2진수 : `111` = 0.111 x 2^3

 

`10101.1101`을 정규화하기 위해 소수점을 맨 앞으로 보낸다.

이때 소수점이 5칸 앞으로 갔기 때문에 5 제곱을 곱해줘야 되는데, 2진수이기 때문에 `0.101011101`에 2^5를 곱한다.

∴ `10101.1101` = 0.101011101 x 2^5

부동소수점 표현

위키백과 - 부동소수점 (부호 비트, 지수, 가수)
출처 : Wikipedia(위키백과)

지수 : 거듭제곱 부분

가수 : 밑에 있는 숫자

 

[32bit] 21.8125 ➜ 정규화 = 0.101011101 x 2^5

[1bit] 맨 앞 bit 부호 ➜ 양수 = 0

[8bit] 지수 부호 = 0, 지수 5를 2진수로 = 0000101

[32 - 1 - 8 = 23bit] 가수 ➜ 0.101011101에서 소수점 뒷부분을 그대로 적어주고 나머지는 0으로 채운다. = 101011101 00000000000000

∴ 00000010110101110100000000000000


실수가 소수점으로 딱 떨어지지 않을 때

소수점 아래 부분이 점점 늘어나다 보면 가수 부분 자리가 모자라는 경우가 발생한다. (ex. 3.1231542…)

가수 부분은 무한정 길어질 수 없기 때문에 가장 근사한 값으로 비트를 잡아줘야 한다.

double의 메모리 길이가 float의 2배이기 때문에 아랫 단위의 미세한 소수점까지 훨씬 더 정밀하게 표현 가능하다.

 

※ 요약

 실수 표현 방식은 정밀도에 의존한다.

 double ➜ float보다 더 아래 부분의 소수점 자리까지 정밀하게 표현 가능하다.

◦ 실수가 정밀하게 표현되지 않아서 발생하는 문제 (ex. 조건식)

더보기

어떤 결괏값이 실수 `1`일 때 내가 원하는 상황을 실행시키는 조건을 만들었다고 해보자.
결괏값이 `1`이 나와줘야 되고 내가 봤을 때는 `1`인데 테스트를 해보니 `0.9999998f`가 나온다.
사실상 거의 `1`인데도 내가 걸었던 조건은 정확하게 실수 표현 방식으로 `1`이 나와야 된다고 했기 때문에 해당 조건이 걸리지 않는 경우가 생긴다.