정수 자료형의 종류와 크기는 다음과 같다.
| 자료형 | 크기(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

#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
만약, 음수를 저장할 필요가 없다면, 같은 공간으로 2배의 범위를 지정할 수 있는 unsigned 정수형을 고려해 볼 수 있다.
unsigned char : 0 ~ 255unsigned short : 0 ~ 65,535unsigned int : 0 ~ 4,294,967,295unsigned long long : 0 ~ 18,446,744,073,709,551,615signed 방식은 가장 왼쪽의 비트를 이용해 부호 표시를 하지만, unsigned 방식은 가장 왼쪽의 비트도 수의 범위를 표현하는데 사용한다.

signed 방식에서는 가장 왼쪽의 비트가 0 이면 양수, 1 이면 음수를 표현한다.
00010100 = 20 (16 + 4)10010100 = -108 (-128 + 16 + 4)#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 의 보수를 취해야 정수 +5 와 -5 를 더했을 때 0 이 되는 것을 확인할 수 있다.

변수는 데이터를 담는 그릇과 같다. 그릇에 용량 이상의 물을 담으면 넘치는 것처럼, 변수에도 데이터 형식의 크기를 넘어선 값을 담으면 넘친다. 이러한 현상을 오버플로(Overflow)라고 한다.
unsigned char 형 변수 a 에 unsigned char 가 담을 수 있는 최대값을 저장하고 a 에 1 을 더해보도록 하겠다.
#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
오버플로된 변수 a 는 unsigned char 가 가질 수 있는 최저값 0 을 갖고 있다.
이는 수를 2 진수로 바꿔보면 쉽게 이해할 수 있다.
unsigned char 의 최대값은 255 이며, 255는 2 진수로 바꾸면 1111 1111 이다.

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

위 처럼 각 데이터 형식의 최대값을 넘어가는 데이터를 저장할 때는 오버플로가 일어나지만 최저값보다 작은 데이터를 저장하면 언더플로(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 형 선언 시 숫자 뒤에 f 를 long double 형 선언 시 숫자 뒤에 l 을 붙이는 것을 권장한다.
실수형에서는 부호가 없는 unsigned 자료형을 지원하지 않는다.
C++의 실수형은 IEEE 754 라는 표준 알고리즘에 기반한 데이터 형식으로 실수를 저장하기 위해 소수점 . 을 유동적으로 움직여서 표현한다.
이를 위해 비트 공간을 아래와 같이 사용한다.

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