기본 타입

기본 타입 (Fundamental types)

C++ 프로그램에서 쓰는 타입 중에서도, 언어가 기본으로 내장해 둔 타입들이 있어요. 이걸 통틀어 기본 타입(fundamental types)이라 불러요. 객체의 크기가 얼마나 되는지, 부호가 있는지 없는지 같은 건 컴파일러와 대상 플랫폼에 따라 달라질 수 있어서, "적어도 이만큼은 보장된다"는 기준을 먼저 잡아 두는 게 좋아요. 여기서 그 기준을 정리해 볼게요. (타입 시스템 전체 개요와 C++ 라이브러리가 제공하는 타입 관련 유틸리티 목록은 type 문서를 같이 보세요.)

출처: cppreference

본문

다음 타입들을 통틀어 기본 타입이라 해요.

  • (cv-한정일 수 있는) void
  • (cv-한정일 수 있는) std::nullptr_t (since C++11)
  • 정수 타입(integral types)
  • 부동소수점 타입(floating-point types)

void

void — 값의 집합이 비어 있는 타입이에요. 완성될 수 없는 불완전 타입이라(그래서 void 타입의 객체는 금지돼요), void의 배열이나 void에 대한 참조는 없어요. 다만 void에 대한 포인터와 void 타입을 반환하는 함수(다른 언어의 프로시저)는 허용돼요.

std::nullptr_t는 널 포인터 리터럴 nullptr의 타입을 가리켜요. 그 자체는 포인터 타입이나 멤버 포인터 타입이 아닌 구별되는 타입이에요. 모든 prvalue가 널 포인터 상수예요. sizeof(std::nullptr_t)sizeof(void*)와 같아요. 이름 std::nullptr_t<cstddef>에 선언돼요. (since C++11)
std::meta::info는 리플렉션(reflection) 값의 타입을 가리켜요. 유일한 널 리플렉션이 있고, 그 외의 모든 리플렉션은 언어 구성을 나타내요. 이름 std::meta::info<meta>에 선언돼요. (since C++26)

정수 타입

int — 기본 정수 타입이에요. 아래 나열한 수정자(modifier) 중 하나를 쓰면 int 키워드는 생략할 수 있어요. 길이 수정자가 없으면 폭이 적어도 16비트임이 보장돼요. 다만 32/64비트 시스템에서는 폭이 적어도 32비트임이 거의 보장돼요(아래 참고).

기본 정수 타입을 수정하는 수정자예요. 어떤 순서로든 섞을 수 있고, 각 그룹에서 하나씩만 타입 이름에 존재할 수 있어요.

  • 부호(signedness):
    • signed — 대상 타입이 부호 있는 표현을 가져요(생략하면 이게 기본)
    • unsigned — 대상 타입이 부호 없는 표현을 가져요
  • 크기(size):
    • short — 대상 타입이 공간에 맞게 최적화되고 폭이 적어도 16비트
    • long — 대상 타입의 폭이 적어도 32비트
    • long long — 대상 타입의 폭이 적어도 64비트 (since C++11)

참고: 모든 타입 지정자처럼 순서는 자유예요. unsigned long long intlong int unsigned long은 같은 타입을 가리켜요.

다음 표는 사용 가능한 표준 정수 타입과 다양한 일반 데이터 모델에서의 속성을 요약해요.

타입 지정자 같은 의미 타입 데이터 모델별 비트 폭
C++ 표준 LP32 ILP32
signed char signed char 적어도 8
unsigned char unsigned char
short short int 적어도 16
short int, signed short, signed short int
unsigned short unsigned short int
unsigned short int
int int 적어도 16
signed, signed int
unsigned unsigned int
unsigned int
long long int 적어도 32
long int, signed long, signed long int
unsigned long unsigned long int
unsigned long int
long long (C++11) long long int 적어도 64
long long int, signed long long, signed long long int
unsigned long long (C++11) unsigned long long int
unsigned long long int

참고: 정수 산술은 부호 있는 정수 타입과 부호 없는 정수 타입에 대해 다르게 정의돼요. 자세한 내용은 산술 연산자 문서, 특히 정수 오버플로 절을 보세요.

std::size_tsizeof 연산자 결과의 부호 없는 정수 타입이에요. sizeof... 연산자와 alignof 연산자 (since C++11)도 마찬가지예요.

| 확장 정수 타입(extended integer types)은 구현 정의예요. 고정 폭 정수 타입은 보통 표준 정수 타입의 별명이라는 점을 참고하세요. | (since C++11) |

booltruefalse 두 값 중 하나를 담을 수 있는 정수 타입이에요. sizeof(bool)의 값은 구현 정의이고 1과 다를 수 있어요.

문자 타입은 문자 표현에 쓰이는 정수 타입이에요.

  • signed char — 부호 있는 문자 표현을 위한 타입
  • unsigned char — 부호 없는 문자 표현을 위한 타입. 객체 표현(원시 메모리)을 조사하는 데도 쓰여요
  • char — 대상 시스템에서 가장 효율적으로 처리할 수 있는 문자 표현용 타입(signed charunsigned char와 같은 표현·정렬을 가지지만, 항상 구별되는 타입). 멀티바이트 문자 문자열은 이 타입으로 코드 유닛을 나타내요. [0, 255] 범위의 unsigned char 값은 char로 변환했다가 다시 unsigned char로 변환하면 원래 값이 나와요 (since C++11). char의 부호 여부는 컴파일러와 대상 플랫폼에 따라 달라져요 — ARM과 PowerPC의 기본은 보통 unsigned, x86과 x64의 기본은 보통 signed예요
  • wchar_t — 넓은 문자 표현용 타입(wide strings 참고). 정수 타입 중 하나와 같은 크기·부호·정렬을 가지지만 구별되는 타입이에요. 실제로는 Linux와 많은 비Windows 시스템에서 32비트로 UTF-32를 담고, Windows에서는 16비트로 UTF-16 코드 유닛을 담아요. 표준은 예전에 지원하는 모든 문자 코드 포인트를 나타낼 만큼 커야 한다고 요구했지만, Windows에서 그 요구를 채울 수 없어 결함으로 간주되어 제거됐어요
  • char16_t — UTF-16 문자 표현용 타입으로, 어떤 UTF-16 코드 유닛(16비트)이든 나타낼 만큼 커야 해요. std::uint_least16_t와 같은 크기·부호·정렬을 가지지만 구별되는 타입이에요 (since C++11)
  • char32_t — UTF-32 문자 표현용 타입으로, 어떤 UTF-32 코드 유닛(32비트)이든 나타낼 만큼 커야 해요. std::uint_least32_t와 같은 크기·부호·정렬을 가지지만 구별되는 타입이에요 (since C++11)
  • char8_t — UTF-8 문자 표현용 타입으로, 어떤 UTF-8 코드 유닛(8비트)이든 나타낼 만큼 커야 해요. unsigned char와 같은 크기·부호·정렬을 가지지만(그래서 char·signed char와 같은 크기·정렬), 구별되는 타입이에요 (since C++20)

최소 비트 수 외에도 C++ 표준은 다음을 보장해요.

1 == sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long)

참고: 이는 바이트가 64비트이고 모든 타입(char 포함)이 64비트 폭이며 sizeof가 모든 타입에 대해 1을 반환하는 극단적인 경우도 허용한다는 뜻이에요.

부동소수점 타입

다음 세 타입과 그 cv-한정 버전을 통틀어 표준 부동소수점 타입이라 해요.

  • float — 단정밀도 부동소수점 타입. 보통 IEEE-754 binary32 형식
  • double — 배정밀도 부동소수점 타입. 보통 IEEE-754 binary64 형식
  • long double — 확장 정밀도 부동소수점 타입. IEEE-754가 규정한 타입에 반드시 대응하지는 않아요. 일부 HP-UX, SPARC, MIPS, ARM64, z/OS 구현은 IEEE-754 binary128 형식을 써요. 가장 잘 알려진 IEEE-754 binary64 확장 형식은 x87 80비트 확장 정밀도 형식으로, 많은 x86·x86-64 구현이 이걸 써요(주목할 예외는 MSVC인데, double과 같은 형식인 binary64로 long double을 구현해요). PowerPC에서는 double-double을 쓸 수 있어요

| 확장 부동소수점 타입(extended floating-point types)은 구현 정의예요. 고정 폭 부동소수점 타입을 포함할 수 있어요. | (since C++23) |

부동소수점 타입은 특별한 값을 지원할 수 있어요.

  • 무한대(양과 음), INFINITY 참고
  • 음의 영 -0.0. 양의 영과 같게 비교되지만 일부 산술 연산에서 의미가 있어요(예: 1.0 / 0.0 == INFINITY, 하지만 1.0 / -0.0 == -INFINITY), 일부 수학 함수에서도요(예: sqrt(std::complex))
  • NaN(not-a-number), 어떤 값과도(자기 자신 포함) 같게 비교되지 않아요. 여러 비트 패턴이 NaN을 나타내요, std::nan, NAN 참고. C++은 시그널링 NaN에 특별히 신경 쓰지 않고(단지 std::numeric_limits::has_signaling_NaN으로 지원 여부를 탐지), 모든 NaN을 quiet로 취급해요

부동소수점 숫자는 산술 연산자 +, -, /, *<cmath>의 여러 수학 함수와 함께 쓸 수 있어요. 내장 연산자와 라이브러리 함수 모두 부동소수점 예외를 일으키고 math errhandling에서 설명한 대로 errno를 설정할 수 있어요.

부동소수점 표현식은 타입이 나타내는 것보다 더 큰 범위와 정밀도를 가질 수 있어요(FLT_EVAL_METHOD 참고). 부동소수점 표현식은 축약(contract)될 수도 있어요. 즉 모든 중간 값이 무한 범위·정밀도를 가진 것처럼 계산될 수 있어요(#pragma STDC FP_CONTRACT 참고). 표준 C++은 부동소수점 연산의 정확도를 제한하지 않아요.

부동소수점 숫자에 대한 일부 연산은 부동소수점 환경의 상태(가장 대표적으로 반올림 방향)에 영향을 받고 또 그것을 수정해요.

부동 타입과 정수 타입 사이에는 암시적 변환이 정의돼 있어요.

부동소수점 타입의 한계·속성에 대한 추가 설명은 부동소수점 타입의 한계와 std::numeric_limits를 보세요.

값의 범위

다음 표는 일반적인 숫자 표현의 한계에 대한 참고 자료를 제공해요.

C++20 이전에는 C++ 표준이 어떤 부호 있는 정수 표현도 허용했고, N비트 부호 있는 정수의 보장된 최소 범위는 -(2^(N-1)-1)에서 +(2^(N-1)-1)(예: 부호 있는 8비트 타입에서 −127부터 127까지)였어요. 이는 1의 보수나 부호-크기 표현의 한계에 해당해요.

하지만 모든 C++ 컴파일러가 2의 보수 표현을 쓰고, C++20부터는 표준이 허용하는 유일한 표현이 됐어요. 보장 범위는 -2^(N-1)에서 +(2^(N-1)-1)(예: 부호 있는 8비트 타입에서 −128부터 127까지)예요.

char에 대한 8비트 1의 보수와 부호-크기 표현은 C++11부터 금지됐어요(CWG issue 1759의 해결을 통해). UTF-8 문자열 리터럴에 쓰인 값 0x80의 UTF-8 코드 유닛이 char 타입 객체에 저장될 수 있어야 하기 때문이에요.

부동소수점 타입 T의 범위는 다음과 같이 정의돼요.

  • 보장된 최소 범위는 T에서 표현 가능한 가장 음의 유한 부동소수점 숫자부터 가장 양의 유한 부동소수점 숫자까지
  • 음의 무한대가 T에서 표현 가능하면, T의 범위는 모든 음의 실수로 확장돼요
  • 양의 무한대가 T에서 표현 가능하면, T의 범위는 모든 양의 실수로 확장돼요

음·양 무한대가 ISO/IEC/IEEE 60559 형식에서 표현 가능하므로, ISO/IEC/IEEE 60559를 따르는 부동소수점 타입의 표현 가능한 값 범위 안에는 모든 실수가 놓여요.

타입 비트 크기 형식 값 범위
근삿값 정확값
character 8 signed
unsigned 0 ~ 255
16 UTF-16
32 UTF-32
integer 16 signed ± 3.27 · 10⁴
unsigned 0 ~ 6.55 · 10⁴ 0 ~ 65535
32 signed ± 2.14 · 10⁹
unsigned 0 ~ 4.29 · 10⁹ 0 ~ 4,294,967,295
64 signed ± 9.22 · 10¹⁸
unsigned 0 ~ 1.84 · 10¹⁹ 0 ~ 18,446,744,073,709,551,615
binary floating-point 32 IEEE-754 min subnormal: ± 1.401,298,4 · 10⁻⁴⁵ / min normal: ± 1.175,494,3 · 10⁻³⁸ / max: ± 3.402,823,4 · 10³⁸
64 IEEE-754 min subnormal: ± 4.940,656,458,412 · 10⁻³²⁴ / min normal: ± 2.225,073,858,507,201,4 · 10⁻³⁰⁸ / max: ± 1.797,693,134,862,315,7 · 10³⁰⁸
80¹ x86 min subnormal: ± 3.645,199,531,882,474,602,528 · 10⁻⁴⁹⁵¹ / min normal: ± 3.362,103,143,112,093,506,263 · 10⁻⁴⁹³² / max: ± 1.189,731,495,357,231,765,021 · 10⁴⁹³²
128 IEEE-754 min subnormal: ± 6.475,175,119,438,025,110,924,438,958,227,646,552,5 · 10⁻⁴⁹⁶⁶ / min normal: ± 3.362,103,143,112,093,506,262,677,817,321,752,602,6 · 10⁻⁴⁹³² / max: ± 1.189,731,495,357,231,765,085,759,326,628,007,016,2 · 10⁴⁹³²
  1. 객체 표현은 보통 32/64비트 플랫폼에서 각각 96/128비트를 차지해요.

참고: 이 타입들의 실제(보장된 최소가 아닌) 한계는 C 숫자 한계 인터페이스와 std::numeric_limits에서 확인할 수 있어요.

데이터 모델

각 구현이 기본 타입의 크기에 대해 내리는 선택을 통틀어 **데이터 모델(data model)**이라 불러요. 널리 받아들여진 네 가지 모델이 있어요.

32비트 시스템:

  • LP32 또는 2/4/4 (int는 16비트, long과 포인터는 32비트) — Win16 API
  • ILP32 또는 4/4/4 (int, long, 포인터가 32비트) — Win32 API, Unix 및 Unix 계열 시스템(Linux, macOS)

64비트 시스템:

  • LLP64 또는 4/4/8 (intlong은 32비트, 포인터는 64비트) — 64비트 ARM(AArch64) 또는 x86-64(x64)를 대상으로 컴파일하는 Win32 API(Windows API라고도 함)
  • LP64 또는 4/8/8 (int는 32비트, long과 포인터는 64비트) — Unix 및 Unix 계열 시스템(Linux, macOS)

다른 모델은 매우 드물어요. 예를 들어 ILP64(8/8/8: int, long, 포인터가 64비트)는 초기 64비트 Unix 시스템(Cray의 UNICOS처럼)에만 나타났어요.

참고

기능 테스트 매크로 표준 기능
__cpp_unicode_characters 200704L (C++11) 새 문자 타입(char16_t, char32_t)
__cpp_char8_t 201811L (C++20) char8_t
202207L (C++23) char8_t 호환성·이식성 수정(UTF-8 문자열 리터럴에서 (unsigned) char 배열의 초기화 허용)

키워드

void, bool, true, false, char, char8_t, char16_t, char32_t, wchar_t, int, short, long, signed, unsigned, float, double

더 알아보기

  • C++ 타입 시스템 전체 개요는 type 문서에서 볼 수 있어요.
  • const-volatility(cv) 지정자·한정자와 저장 기간 지정자 문서를 보면 타입 한정 규칙을 이어서 확인할 수 있어요.
  • cppreference의 기본 타입 원문에서 결함 보고(defect report) 기록을 더 볼 수 있어요.