기본 데이터 타입
정수·실수·문자·논리 타입의 저장 방식과 표현 범위를 비교하고 구현 환경에 맞는 데이터 타입을 선택합니다.
int score = 100;에서 int는 값의 종류뿐 아니라 표현 범위와 연산 규칙도 정합니다. 같은 100이라도 개수, 온도, 문자 코드 중 무엇을 뜻하는지에 따라 알맞은 타입이 달라집니다. 이 절에서는 기본 데이터 타입(Data Type)을 고르고, 현재 실행 환경에서 크기와 범위를 확인합니다.
첫 그림은 기본 타입을 표 암기가 아니라 저장 폭, 범위, 부호 해석, 실수 정밀도를 함께 확인하는 판독 순서로 묶습니다.
플랫폼마다 크기가 달라질 수 있는 부분은 sizeof와 std::numeric_limits로 확인한다는 기준을 먼저 둡니다.
그림과 표의 크기·정밀도는 일반적인 구현 기준이며, char의 signed 여부, bool 크기, long double 정밀도처럼 구현별로 달라질 수 있는 값은 직접 확인해야 합니다.
C++ · TYPE AND SCOPE
타입은 값의 의미와 표현 범위부터 선택한다
흔한 바이트 수와 표준 보장을 구분하고, 현재 구현의 범위·정밀도·인코딩을 확인합니다.
| 타입군 | 먼저 묻는 질문 | 표준 계약 · 주의점 | 현재 구현 확인 |
|---|---|---|---|
| 부호 있는 정수 | 입력과 중간 계산 값의 범위는? | short → int → long → long long은 저장 공간이 줄지 않는다. 표현 범위를 넘는 signed 산술은 정의되지 않는다. |
sizeof(T), std::numeric_limits<T> |
| 부호 없는 정수 | 순환 산술이나 비트 패턴이 실제 의미인가? | 대응 signed 타입과 같은 폭 N, 범위 0 … 2^N−1, 산술은 2^N을 법으로 한다. |
std::numeric_limits<T>::max(), signed/unsigned 혼합 식 점검 |
| 부동 소수점 | 필요한 정밀도와 허용 오차 모델은? | double은 float 이상, long double은 double 이상의 정밀도를 제공하지만 같은 표현일 수도 있다. |
radix, digits10, denorm_min(), lowest()/max(), is_iec559 |
| 문자 · 코드 단위 | 어떤 리터럴·문자열 인코딩을 다루는가? | char 부호와 일반·wide 인코딩은 구현 정의다. char8_t/16_t/32_t는 각 UTF 인코딩의 코드 단위다. |
CHAR_BIT, sizeof, 리터럴 prefix와 입출력 인코딩 |
| 논리 | 값이 계산량이 아니라 조건의 상태인가? | bool의 값은 true와 false다. 크기는 구현 정의이며 정수 개수 저장용 타입이 아니다. 두 상태를 넘는 이름 있는 상태 집합이면 enum을 검토한다. |
sizeof(bool), boolalpha 출력 여부 |
- 부호 있는 정수
- 질문 입력과 중간 계산 값의 범위는?
- 계약
short → int → long → long long순서에서 저장 공간은 줄지 않으며, 범위를 넘는 signed 산술은 정의되지 않습니다. - 확인
sizeof와std::numeric_limits<T> - 부호 없는 정수
- 질문 순환 산술이나 비트 패턴이 실제 의미인가?
- 계약 대응 signed 타입과 같은 폭
N이며 범위는0 … 2^N−1이고 산술은2^N을 법으로 합니다. - 확인 최댓값과 signed/unsigned 혼합 식
- 부동 소수점
- 질문 필요한 정밀도와 허용 오차 모델은?
- 계약
double은float이상,long double은double이상의 정밀도를 제공하지만 같은 표현일 수도 있습니다. - 확인
radix,digits10,denorm_min(),lowest()/max(),is_iec559 - 문자 · 코드 단위
- 질문 어떤 리터럴·문자열 인코딩을 다루는가?
- 계약 일반
char의 부호와 ordinary·wide 인코딩은 구현이 정합니다.char8_t/16_t/32_t는 각각 UTF-8/16/32 코드 단위입니다. - 확인
CHAR_BIT, 크기, prefix, 입출력 인코딩 - 논리
- 질문 계산량이 아니라 조건의 상태인가?
- 계약
bool은true와false를 표현하며 크기는 구현 정의입니다. 두 상태를 넘는 이름 있는 상태 집합이면enum을 검토합니다. - 확인
sizeof(bool)과boolalpha출력
고정폭이나 wire format이 요구되면 타입 이름만 선택하지 말고 <cstdint>의 제공 여부, 바이트 순서, 직렬화 규칙을 별도 계약으로 둡니다.
데이터 타입이란 무엇인가?
다음 그림은 변수에 타입을 붙이는 순간 값의 모양, 메모리 폭, 연산 규칙, 오류 가능성이 함께 정해진다는 점을 정리합니다.
C++ · TYPE AND SCOPE
하나의 타입이 표현·연산·객체 계약을 함께 정한다
가능한 값, 연산 규칙, 크기와 정렬을 함께 확인해야 실행 결과를 설명할 수 있습니다.
값의 의미에 맞춰 타입을 정하면 아래 세 계약이 함께 결정됩니다.
- 표현 계약
- 가능한 값과 범위, 정밀도, 문자 코드 단위를 정합니다.
- 연산 계약
- 산술·비교·변환, 오버플로와 반올림 규칙을 정합니다.
- 객체 계약
- 크기·정렬과 구현별 표현 특성을 정합니다.
컴파일 결과 · 실행 의미
세 계약이 함께 관찰 가능한 동작을 만듭니다.
검증할 때는 sizeof, std::numeric_limits, 경계값 테스트로 현재 구현과 의도를 대조합니다.
같은 숫자처럼 보여도 타입이 다르면 표현 가능 범위와 연산·변환 결과가 달라질 수 있습니다. 특정 바이트 배열을 모든 환경의 공통 표현으로 가정하지 않습니다.
데이터 타입은 프로그램이 데이터를 해석하고 처리하는 방식을 결정하는 속성입니다.
변수를 선언할 때 특정 데이터 타입을 지정하면, 컴파일러는 해당 변수가 어떤 종류의 데이터를 저장할지, 얼마나 많은 메모리 공간을 할당해야 할지, 그리고 그 데이터를 어떻게 연산해야 할지를 알게 됩니다.
예를 들어, 숫자 10을 저장한다고 할 때, 이 10이 정수 10인지, 아니면 10.00과 같은 실수 10인지에 따라 컴퓨터는 내부적으로 다른 방식으로 저장하고 처리합니다.
데이터 타입은 이처럼 데이터의 본질과 그것을 다루는 규칙을 명시하는 역할을 합니다.
정수 타입 (Integer Types)
정수는 소수점 이하가 없는 숫자를 의미합니다.
C++에서는 다양한 크기의 정수 타입을 제공하여, 필요에 따라 효율적으로 메모리를 사용할 수 있도록 합니다.
| 타입 | 표준 최소 폭 | 표현 범위 | 흔한 sizeof | 핵심 용도와 주의점 |
|---|---|---|---|---|
char | 8비트 이상 | 부호 해석은 구현이 정함 | 1 | 일반 문자 코드 단위이자 C++ 바이트. signed char와 다름 |
short | 16비트 | ~ | 2 | 작은 정수. 실제 폭과 범위는 구현에서 확인 |
int | 16비트 | ~ | 4 | 일반 정수 연산의 출발점 |
long | 32비트 | ~ | 4 또는 8 | ABI에 따라 폭이 달라지기 쉬움 |
long long | 64비트 | ~ | 8 | 표준 정수 타입 중 최소 폭이 가장 큼 |
여기서 은 해당 정수 타입의 값 표현 폭입니다. C++ 표준은 signed char → short → int → long → long long 순서에서 뒤 타입이 앞 타입보다 적은 저장 공간을 제공하지 않으며, 위 표의 최소 폭 이상이어야 한다고 정합니다. 흔한 sizeof 값은 예시일 뿐입니다.
sizeof(char)는 항상 1이지만, 이 1은 C++가 정의한 바이트 한 칸입니다. 한 바이트의 비트 수는 CHAR_BIT로 확인하며 반드시 8이라고 가정할 수는 없습니다. char는 signed char, unsigned char와 서로 다른 타입이고, 일반 char가 어느 부호 표현을 따르는지는 구현이 정합니다.
부호 있는 정수와 부호 없는 정수:
short, int, long, long long은 signed를 생략한 표기이며 양수와 음수를 표현합니다. 일반 char의 부호는 앞서 본 것처럼 별도 구현 정의입니다.
각 표준 부호 있는 정수 타입에는 같은 폭 을 가진 대응 부호 없는 타입이 있습니다. 부호 없는 타입의 범위는 0부터 이고, 산술은 을 법으로 계산됩니다. 따라서 최댓값에서 1을 더하거나 0에서 1을 빼면 범위의 반대쪽으로 순환합니다.
이 순환이 프로토콜·비트 마스크처럼 의도한 의미라면 unsigned가 알맞지만, 단순히 "음수가 없을 것"이라는 이유만으로 선택하면 뺄셈과 signed/unsigned 혼합 비교에서 버그를 숨길 수 있습니다. 수량 차이가 음수가 될 수 있거나 오류를 음수 값으로 표현한다면 먼저 signed 타입을 검토하세요. signed 산술이 표현 범위를 넘는 경우는 unsigned 순환과 달리 정의되지 않은 동작입니다.
#include <climits> // CHAR_BIT
#include <iostream>
#include <limits> // 각 타입의 최대/최소 값을 확인하기 위해 포함
int main() {
char singleChar = 'A'; // 단일 문자 저장
short smallNumber = 100;
int integerValue = 12345; // 가장 일반적으로 사용
long bigNumber = 1234567890L; // L 접미사는 long 타입을 명시 (선택적)
long long veryBigNumber = 9000000000000000000LL; // LL 접미사는 long long 타입을 명시
unsigned int positiveOnly = 42U; // U 접미사는 unsigned 타입을 명시
std::cout << "char: " << singleChar << " (크기: " << sizeof(char) << "바이트)" << std::endl;
std::cout << "short: " << smallNumber << " (크기: " << sizeof(short) << "바이트)" << std::endl;
std::cout << "int: " << integerValue << " (크기: " << sizeof(int) << "바이트)" << std::endl;
std::cout << "long: " << bigNumber << " (크기: " << sizeof(long) << "바이트)" << std::endl;
std::cout << "long long: " << veryBigNumber << " (크기: " << sizeof(long long) << "바이트)" << std::endl;
std::cout << "unsigned int: " << positiveOnly << " (크기: " << sizeof(unsigned int) << "바이트)" << std::endl;
std::cout << "한 바이트의 비트 수: " << CHAR_BIT << std::endl;
// 각 타입의 최대/최소 값 확인 (limits 헤더 필요)
std::cout << "int 최대값: " << std::numeric_limits<int>::max() << std::endl;
std::cout << "int 최소값: " << std::numeric_limits<int>::min() << std::endl;
std::cout << "unsigned int 최대값: " << std::numeric_limits<unsigned int>::max() << std::endl;
return 0;
}sizeof 연산자는 특정 데이터 타입이나 변수가 메모리에서 차지하는 C++ 바이트 수를 알려줍니다.
std::numeric_limits는 <limits> 헤더에 정의된 템플릿 클래스로, 각 숫자 타입의 최솟값/최댓값 등 다양한 정보를 얻을 수 있게 해줍니다.
위 프로그램을 빌드해 실행한 뒤 int의 크기·최솟값·최댓값을 한 묶음으로 적어 보세요. sizeof(int)가 4로 나왔다면 저장 공간은 4 C++ 바이트이며, 바이트당 비트 수는 별도로 출력한 CHAR_BIT에서 읽습니다. 표의 흔한 값과 달라도 곧바로 오류는 아닙니다. 표현 범위는 타입 이름이나 크기 추측 대신 실제 numeric_limits 결과와 대조합니다.
부동 소수점 타입 (Floating-Point Types)
부동 소수점 타입은 소수점이 있는 숫자(실수)를 저장하는 데 사용됩니다.
정수 타입과 달리, 실수는 컴퓨터 내부에서 약간의 오차를 가질 수 있습니다.
| 타입 | 표준이 보장하는 관계 | 흔한 구현 예시 | 직접 확인할 속성 |
|---|---|---|---|
float | 표준 부동 소수점 타입 | 4바이트, 약 6자리 십진 정밀도 | radix, digits10, denorm_min(), lowest(), max() |
double | float 이상의 정밀도와 값 집합 | 8바이트, 약 15자리 십진 정밀도 | radix, digits10, max_digits10, is_iec559 |
long double | double 이상의 정밀도와 값 집합 | 8·12·16바이트 등 구현마다 다름 | sizeof, radix, digits10, lowest(), max(), is_iec559 |
정밀도: 부동 소수점 타입은 유효 숫자 자릿수로 정밀도를 표현합니다.
흔한 radix-2 ISO 60559 구현에서는 float과 double의 digits10이 각각 약 6과 15입니다. 이는 제한된 자릿수의 십진 값을 타입으로 변환했다가 되돌릴 때 보존할 수 있는 보수적인 십진 변환 정밀도이지, 그 자릿수 이하의 모든 십진 분수가 내부에서 정확히 표현된다는 뜻은 아닙니다. 실제 기수와 표현 방식, 연산 정확도는 radix, is_iec559 등으로 확인해야 합니다. long double은 double보다 적은 정밀도를 가질 수는 없지만 같은 표현을 사용할 수도 있으므로, 이름만 보고 정밀도가 늘어난다고 가정하지 마세요.
부동 소수점 타입에서 std::numeric_limits<T>::min()은 가장 작은 양의 정규화 값입니다. 서브노멀 값을 지원하면 그보다 작은 양수도 있으며, denorm_min()이 가장 작은 양의 서브노멀 값을 돌려줍니다. 서브노멀을 지원하지 않으면 denorm_min()은 min()과 같습니다. 가장 작은 유한값은 lowest(), 가장 큰 유한값은 max()로 확인합니다.
부동 소수점 오차: 흔한 radix-2 구현에서는 0.1과 같은 일부 십진 분수를 정확히 표현할 수 없습니다. 다른 기수의 구현도 가능하므로 현재 타입의 radix를 확인해야 합니다.
이로 인해 미세한 오차가 발생할 수 있습니다. 비교할 때는 모든 값에 하나의 고정 epsilon을 기계적으로 적용하지 말고, 측정 단위와 값의 크기, 계산 횟수에 맞는 절대·상대 허용 오차나 도메인 규칙을 정해야 합니다.
#include <iostream>
#include <iomanip> // std::fixed, std::setprecision을 사용하기 위해 포함
int main() {
float pi_float = 3.1415926535F; // F 접미사는 float 타입을 명시
double pi_double = 3.14159265358979323846; // 기본적으로 double 타입으로 간주
long double pi_long_double = 3.14159265358979323846L; // L 접미사는 long double 타입을 명시
std::cout << std::fixed << std::setprecision(20); // 소수점 이하 20자리까지 고정 출력
std::cout << "float (pi): " << pi_float << " (크기: " << sizeof(float) << "바이트)" << std::endl;
std::cout << "double (pi): " << pi_double << " (크기: " << sizeof(double) << "바이트)" << std::endl;
std::cout << "long double (pi): " << pi_long_double << " (크기: " << sizeof(long double) << "바이트)" << std::endl;
// 부동 소수점 오차 예시
double result = 0.1 + 0.2;
std::cout << "0.1 + 0.2 = " << result << std::endl; // 정확히 0.3이 아닐 수 있음
return 0;
}std::fixed와 std::setprecision은 <iomanip> 헤더에 정의되어 있으며, 실수를 출력할 때 소수점 이하 자릿수를 제어하는 데 사용됩니다.
setprecision(20)은 저장 정밀도를 늘리지 않습니다. 이미 저장된 값을 소수점 이하 20자리로 표시하므로, float에 처음 저장할 때 잃은 자릿수가 다시 생기지 않습니다. pi_float와 pi_double의 뒤쪽 출력이 다른 이유를 저장 단계와 표시 단계로 나누어 설명해 보세요.
문자 타입 (Character Types)
문자 타입은 문자의 화면 모양 자체가 아니라 문자열 인코딩을 이루는 코드 단위(code unit)를 저장합니다. 문자 하나가 항상 코드 단위 하나라는 뜻은 아닙니다.
char: 일반 문자·문자열 리터럴의 코드 단위입니다. 크기는 1 C++ 바이트지만 일반 리터럴 인코딩은 구현이 정하므로 ASCII로 고정하지 않습니다.wchar_t: wide 리터럴의 코드 단위입니다. 기반 정수 타입과 wide 리터럴 인코딩이 구현 정의이므로 그 자체를 이식 가능한 Unicode 저장 타입으로 볼 수 없습니다.char8_t: C++20부터 UTF-8 코드 단위를 표현합니다.u8"..."리터럴의 원소 타입입니다.char16_t,char32_t: 각각 UTF-16과 UTF-32 리터럴의 코드 단위를 표현합니다. UTF-16에서는 하나의 Unicode 스칼라 값이 두 코드 단위를 사용할 수 있습니다.
#include <iostream>
int main() {
char grade = 'A'; // ordinary literal encoding의 한 코드 단위
std::cout << "내 학점: " << grade << std::endl;
std::cout << "이 구현의 코드 단위 값: "
<< static_cast<unsigned int>(static_cast<unsigned char>(grade))
<< std::endl;
return 0;
}논리 타입 (Boolean Type)
논리 타입은 참(true) 또는 거짓(false)이라는 두 가지 값만을 저장합니다.
프로그램의 조건문이나 반복문 등에서 특정 조건의 만족 여부를 판단할 때 사용됩니다.
bool:true또는false값을 가집니다. 대부분의 구현에서는 1바이트로 보이지만, 정확한 크기는sizeof(bool)로 확인합니다.
#include <iostream>
int main() {
bool isCppFun = true; // 참을 의미하는 true
bool hasErrors = false; // 거짓을 의미하는 false
std::cout << "C++은 재밌는가? " << isCppFun << std::endl; // true는 1로, false는 0으로 출력됨
std::cout << "오류가 있는가? " << hasErrors << std::endl;
// 논리 연산
if (isCppFun) {
std::cout << "아주 재미있습니다!" << std::endl;
} else {
std::cout << "더 노력해야겠네요..." << std::endl;
}
return 0;
}bool 타입의 값을 std::cout으로 출력하면 true는 1로, false는 0으로 표시됩니다.
만약 true나 false를 문자 그대로 출력하고 싶다면 std::boolalpha 조작자를 사용할 수 있습니다.
std::cout << std::boolalpha << "C++은 재밌는가? " << isCppFun << std::endl; // "true"로 출력마지막으로 기본 타입을 고를 때는 단순히 "숫자냐 문자냐"만 보지 말고, 값의 의미, 필요한 범위, 부호·순환 산술 여부, 정밀도와 오차 모델, 인코딩, 출력 방식을 순서대로 확인해야 합니다. 정확한 폭이나 표현 특성이 외부 형식의 계약이라면 <cstdint>의 고정폭 타입 제공 여부와 직렬화 규칙까지 별도로 확인하세요.
직접 타입을 고른다.
어떤 구현의 확인 결과가 CHAR_BIT=8, unsigned char의 최댓값이 255라고 주어졌다. 최대 300개인 참가자 수를 이 타입 하나에 저장해도 되는가? 온도를 −10부터 40까지 정수로 기록할 때, 음수 입력을 그대로 다뤄야 한다면 부호 없는 타입을 고르는 이유가 있는가? 두 상태인 ‘접수 완료 여부’에는 어떤 기본 타입이 알맞은가?
선택 근거 확인
300은 255보다 크므로 해당 unsigned char의 범위를 넘습니다. 더 넓은 정수 타입의 실제 범위에서 300을 표현하는지 확인합니다. 온도에는 음수를 표현하는 signed 타입을 먼저 검토하며, ‘음수가 안 된다’는 가정을 실제 입력에 강요하지 않습니다. 완료 여부는 bool로 표현할 수 있습니다. 타입 선택의 근거는 흔한 바이트 수가 아니라 필요한 값의 의미와 범위입니다.