정수형

정수 자료형의 종류와 크기는 다음과 같다.

자료형 크기(byte) 범위
char (__int8) 1 byte -128 ~ 127
unsigned char 1 byte 0 ~ 255
short 2 byte -32,768 ~ 32,767
unsigned short 2 byte 0 ~ 65,535
int 4 byte -2,147,483,648 ~ 2,147,483,647
unsigned int 4 byte 0 ~ 4,294,967,295
long 4 byte -2,147,483,648 ~ 2,147,483,647
unsigned long 4 byte 0 ~ 4,294,967,295
long long (__int64) 8 byte -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
unsigned long long 8 byte 0 ~ 18,446,744,073,709,551,615

int 형과 long 형의 경우 겉보기에는 같은 자료형처럼 보일 수 있지만 완전 같은 자료형은 아니다.

int 형은 16 bit 이하의 CPU가 거의 사라졌기 때문에 사실상 4 byte 라고 봐도 무방하지만 long 형의 경우 OS와 애플리케이션의 bit 에 따라 크기가 4 byte 보다 더 커질 수 있다.

정수형의 크기

1 byte = 8 bit

Untitled

#include <iostream>

int main()
{
	char Char = 0;
	short Short = 0;
	int Int = 0;
	long long Long = 0;

	unsigned char UInt_8 = 0;
	unsigned short UShort = 0;
	unsigned int UInt = 0;
	unsigned long long ULong = 0;

	std::cout << "sizeof(Char)   : " << sizeof(Char) << std::endl;
	std::cout << "sizeof(Short)  : " << sizeof(Short) << std::endl;
	std::cout << "sizeof(Int)    : " << sizeof(Int) << std::endl;
	std::cout << "sizeof(Long)   : " << sizeof(Long) << std::endl;
	std::cout << "sizeof(UInt_8) : " << sizeof(UInt_8) << std::endl;
	std::cout << "sizeof(UShort) : " << sizeof(UShort) << std::endl;
	std::cout << "sizeof(UInt)   : " << sizeof(UInt) << std::endl;
	std::cout << "sizeof(ULong)  : " << sizeof(ULong) << std::endl;

	return 0;
}
sizeof(Char)   : 1
sizeof(Short)  : 2
sizeof(Int)    : 4
sizeof(Long)   : 8
sizeof(UInt_8) : 1
sizeof(UShort) : 2
sizeof(UInt)   : 4
sizeof(ULong)  : 8

unsigned 정수형

만약, 음수를 저장할 필요가 없다면, 같은 공간으로 2배의 범위를 지정할 수 있는 unsigned 정수형을 고려해 볼 수 있다.

signed 방식은 가장 왼쪽의 비트를 이용해 부호 표시를 하지만, unsigned 방식은 가장 왼쪽의 비트도 수의 범위를 표현하는데 사용한다.

image.png

signed 방식에서는 가장 왼쪽의 비트가 0 이면 양수, 1 이면 음수를 표현한다.

#include <iostream>

int main()
{
	char Char = 0b10010100; // -108 = (-128 + 16 + 4)
	unsigned char UChar = 0b10010100; // 148 = (128 + 16 + 4)

	std::cout << static_cast<int>(Char) << std::endl;
	std::cout << static_cast<int>(UChar) << std::endl;

	return 0;
}
-108
148

2의 보수볍

컴퓨터에서 음의 정수를 표현할 때에는 2 의 보수를 취해야 한다.

2 의 보수법은 다음과 같은 과정을 거친다.

  1. 1 의 보수를 취한다.
  2. 1 을 더한다.

Untitled

2 의 보수를 취해야 정수 +5-5 를 더했을 때 0 이 되는 것을 확인할 수 있다.

Untitled

오버플로 & 언더플로

변수는 데이터를 담는 그릇과 같다. 그릇에 용량 이상의 물을 담으면 넘치는 것처럼, 변수에도 데이터 형식의 크기를 넘어선 값을 담으면 넘친다. 이러한 현상을 오버플로(Overflow)라고 한다.

unsigned char 형 변수 aunsigned char 가 담을 수 있는 최대값을 저장하고 a1 을 더해보도록 하겠다.

#include <iostream>

int main()
{
	unsigned char a = UCHAR_MAX;			
	std::cout << "a = " << static_cast<int>(a) << std::endl;

	a = a + 1;
	std::cout << "a = " << static_cast<int>(a) << std::endl;

	return 0;
}
a = 255
a = 0

오버플로된 변수 aunsigned char 가 가질 수 있는 최저값 0 을 갖고 있다.

이는 수를 2 진수로 바꿔보면 쉽게 이해할 수 있다.

unsigned char 의 최대값은 255 이며, 255는 2 진수로 바꾸면 1111 1111 이다.

image.png

여기에 1 을 더하면 1 0000 0000 이 된다.

그러나 unsigned char 는 8 개의 비트만 담을 수 있으므로 넘쳐 흐른 왼쪽의 비트는 버리고 오른쪽 8 개 비트 0000 0000 만 보관하게 된다.

image.png

위 처럼 각 데이터 형식의 최대값을 넘어가는 데이터를 저장할 때는 오버플로가 일어나지만 최저값보다 작은 데이터를 저장하면 언더플로(Underflow)가 일어난다.

unsigned char 형식 변수에 -1 을 담으려하면 실제로는 255 가 저장된다.

#include <iostream>

int main()
{
	unsigned char a = -1;			
	std::cout << "a = " << static_cast<int>(a) << std::endl;

	return 0;
}
a = 255

실수형 (부동 소수점형)

실수 자료형의 종류와 크기는 다음과 같다.

자료형 크기(byte) 범위
float 4 byte 약 ± 3.4 * 10^(-37) 이상 ± 3.4 * 10^38 이하
double 8 byte 약 ± 1.7 * 10^(-307) 이상 ± 1.7 * 10^308 이하
long double 8 byte 이상 double 보다 넓음
#include <iostream>

int main()
{
	float Float = 1.2345f;
	double Double = 1.2345;
	long double LDouble = 1.2345l;

	std::cout << "sizeof(Float)   : " << sizeof(Float) << std::endl;
	std::cout << "sizeof(Double)  : " << sizeof(Double) << std::endl;
	std::cout << "sizeof(LDouble) : " << sizeof(LDouble) << std::endl;

	return 0;
}
sizeof(Float)   : 4
sizeof(Double)  : 8
sizeof(LDouble) : 8

float 형 선언 시 숫자 뒤에 flong double 형 선언 시 숫자 뒤에 l 을 붙이는 것을 권장한다.

실수형에서는 부호가 없는 unsigned 자료형을 지원하지 않는다.

부동 소수점 원리

C++의 실수형은 IEEE 754 라는 표준 알고리즘에 기반한 데이터 형식으로 실수를 저장하기 위해 소수점 . 을 유동적으로 움직여서 표현한다.

이를 위해 비트 공간을 아래와 같이 사용한다.

Untitled

float 형 맨 왼쪽 1 비트를 부호, 그 다음 8 비트를 지수, 그 다음 23 비트를 가수부로 사용한다.

double 형 맨 왼쪽 1 비트를 부호, 그 다음 11 비트를 지수, 그 다음 52 비트를 가수부로 사용한다.

이 과정에서 저장 공간은 한정되어 있기 때문에 소수점 절삭으로 인한 오차가 발생한다. 따라서 **실수형은 항상 ‘근삿값’**이라는 것을 기억해야 한다.

#include <iostream>

int main()
{
	float Float = 1.234f;
	double Double = 1.234;

	std::cout << "Float  = " << Float << std::endl;
	std::cout << "Double = " << Double << std::endl;

	if (Float == Double)
		std::cout << "두 수가 같습니다.";
	else
		std::cout << "두 수가 다릅니다.";

	return 0;
}
Float  = 1.234
Double = 1.234
두 수가 다릅니다.

문자형

문자 자료형의 종류와 크기는 다음과 같다.

| --- | --- | --- |

문자형은 문자를 저장하며 아스키코드 값에 따라 숫자로도 값을 할당할 수 있다.

wchar_t 는 유니코드 문자를 나타낸다. 유니코드란 전 세계 모든 문자에 대해 유일 코드를 부여한 것으로 대표적인 표기 방식으로는 UTF8, UTF16 이 있다.

문자형은 문자의 표현을 목적으로 정의된 자료형이지만 정수의 형태로 표현되고, 실제 문자형 변수에 저장되는 것은 정수이다.

#include <iostream>

int main()
{
	// 문자형 선언
	char C = 'a';
	unsigned char UC = 65; // 아스키 코드값으로 할당
	wchar_t WC = L'안';    // 유니코드라는 것을 인식시키기 위해 앞에 L을 붙힙니다.

	std::cout << " C : " << C << std::endl;
	std::cout << "UC : " << UC << std::endl;

	// 유니코드 출력
	std::wcout.imbue(std::locale("kor"));
	std::wcout << "WC : " << WC << std::endl << std::endl;

	std::cout << "sizeof(C)  : " << sizeof(C) << std::endl;
	std::cout << "sizeof(UC) : " << sizeof(UC) << std::endl;
	std::cout << "sizeof(WC) : " << sizeof(WC) << std::endl;

	return 0;
}
 C : a
UC : A
WC : 안

sizeof(C)  : 1
sizeof(UC) : 1
sizeof(WC) : 2