정수 리터럴

정수 리터럴 (Integer literal)

정수 리터럴(integer literal) 은 정수 타입의 값을 표현식에 직접 쓸 수 있게 해 주는 리터럴이에요.

출처: cppreference

본문

문법 (Syntax)

정수 리터럴은 다음 형태를 가져요.

decimal-literal integer-suffix(optional)   (1)
octal-literal   integer-suffix(optional)   (2)
hex-literal     integer-suffix(optional)   (3)
binary-literal  integer-suffix(optional)   (4) (C++14부터)

여기서

  • decimal-literal 은 0이 아닌 십진 숫자(19) 뒤에 십진 숫자(09)가 0개 이상 오는 것
  • octal-literal 은 숫자 0 뒤에 8진 숫자(0~7)가 0개 이상 오는 것
  • hex-literal0x 또는 0X 문자 시퀀스 뒤에 16진 숫자(0-9, a, A, b, B, c, C, d, D, e, E, f, F)가 1개 이상 오는 것
  • binary-literal0b 또는 0B 문자 시퀀스 뒤에 이진 숫자(0, 1)가 1개 이상 오는 것

integer-suffix 는 제공되면 다음 중 하나 또는 둘 다를 포함할 수 있어요 (둘 다 제공되면 아무 순서로 와도 돼요).

  • unsigned-suffix (u 또는 U 문자)
  • 다음 중 하나:
    • long-suffix (l 또는 L 문자)
    • long-long-suffix (ll 또는 LL 문자 시퀀스) (C++11부터)
    • size-suffix (z 또는 Z 문자) (C++23부터)

선택적 단일 따옴표 '를 숫자 사이에 구분자로 넣을 수 있어요. 리터럴 값을 정할 때는 무시돼요. (C++14부터)

정수 리터럴은 (어떤 리터럴이든) 기본 표현식(primary expression)이에요.

설명 (Explanation)

  1. 십진 정수 리터럴 (밑 10)
  2. 8진 정수 리터럴 (밑 8)
  3. 16진 정수 리터럴 (밑 16, 'a''f' 문자는 십진 1015를 나타냄)
  4. 이진 정수 리터럴 (밑 2)

정수 리터럴의 첫 숫자가 가장 중요한 자리예요.

예시. 다음 변수들은 같은 값으로 초기화돼요.

int d = 42;
int o = 052;
int x = 0x2a;
int X = 0X2A;
int b = 0b101010; // C++14

예시. 다음 변수들도 같은 값으로 초기화돼요.

unsigned long long l1 = 18446744073709550592ull;       // C++11
unsigned long long l2 = 18'446'744'073'709'550'592llu; // C++14
unsigned long long l3 = 1844'6744'0737'0955'0592uLL;   // C++14
unsigned long long l4 = 184467'440737'0'95505'92LLU;   // C++14

리터럴의 타입 (The type of the literal)

정수 리터럴의 타입은 값이 들어갈 수 있는 목록 중 첫 번째 타입이에요. 목록은 숫자 밑과 어떤 integer-suffix 를 썼는지에 따라 달라요.

접미사 십진 밑 이진·8진·16진 밑
(없음) int, long int, long long int(C++11부터) int, unsigned int, long int, unsigned long int, long long int(C++11부터), unsigned long long int(C++11부터)
u 또는 U unsigned int, unsigned long int, unsigned long long int(C++11부터) unsigned int, unsigned long int, unsigned long long int(C++11부터)
l 또는 L long int, unsigned long int(C++11까지), long long int(C++11부터) long int, unsigned long int, long long int(C++11부터), unsigned long long int(C++11부터)
l/Lu/U 둘 다 unsigned long int, unsigned long long int(C++11부터) unsigned long int, unsigned long long int(C++11부터)
ll 또는 LL long long int(C++11부터) long long int(C++11부터), unsigned long long int(C++11부터)
ll/LLu/U 둘 다 unsigned long long int(C++11부터) unsigned long long int(C++11부터)
z 또는 Z std::size_t의 부호 있는 버전(C++23부터) std::size_t의 부호 있는 버전(C++23부터) / std::size_t(C++23부터)
z/Zu/U 둘 다 std::size_t(C++23부터) std::size_t(C++23부터)

size-suffix 가 없는(C++23부터) 정수 리터럴의 값이 접미사/밑 조합이 허용하는 어떤 타입에도 들어가지 못할 때, 컴파일러가 리터럴 값을 표현할 수 있는 확장 정수 타입(__int128 같은)을 지원하면 그 리터럴에 그 확장 정수 타입을 줄 수 있어요. 그렇지 않으면 프로그램은 규칙 위반이에요.

참고 (Notes)

  • 정수 리터럴의 문자는 대소문자를 구분하지 않아요. 0xDeAdBeEfU0XdeadBEEFu는 같은 수를 나타내요 (long-long-suffix 는 하나의 예외로 ll 또는 LL만 되고 lL이나 Ll은 안 돼요, C++11부터).
  • 음의 정수 리터럴은 없어요. -1 같은 표현식은 단항 마이너스 연산자를 리터럴이 나타내는 값에 적용하는 것이고 여기엔 암시적 타입 변환이 개입할 수 있어요.
  • C99 이전의 C(C++은 아님)에서는 long int에 안 들어가는 접미사 없는 십진 값이 unsigned long int 타입을 가질 수 있었어요.
  • #if#elif의 제어 표현식에서 쓰일 때 모든 부호 있는 정수 상수는 std::intmax_t 타입이고 모든 부호 없는 정수 상수는 std::uintmax_t 타입인 것처럼 행동해요. (C++11부터)
  • 최대 먹기(maximal munch) 때문에, eE로 끝나는 16진 정수 리터럴은 뒤에 연산자 +-가 오면 연산자와 공백이나 괄호로 분리해야 해요.
auto x = 0xE+2.0;   // error
auto y = 0xa+2.0;   // OK
auto z = 0xE +2.0;  // OK
auto q = (0xE)+2.0; // OK

그렇지 않으면 단일 무효한 전처리 숫자 토큰이 만들어져 이후 분석이 실패해요.

기능 테스트 매크로: __cpp_binary_literals(201304L, C++14, 이진 리터럴), __cpp_size_t_suffix(202011L, C++23, std::size_t와 그 부호 있는 버전의 리터럴 접미사).

예제 (Example)

#include <cstddef>
#include <iostream>
#include <type_traits>

int main()
{
    std::cout << 123 << '\n'
              << 0123 << '\n'
              << 0x123 << '\n'
              << 0b10 << '\n'
              << 12345678901234567890ull << '\n'
              << 12345678901234567890u << '\n'; // the type is unsigned long long
                                                // even without a long long suffix

//  std::cout << -9223372036854775808 << '\n'; // error: the value
               // 9223372036854775808 cannot fit in signed long long, which is the
               // biggest type allowed for unsuffixed decimal integer literal
    std::cout << -9223372036854775808u << '\n'; // unary minus applied to unsigned
               // value subtracts it from 2^64, this gives 9223372036854775808
    std::cout << -9223372036854775807 - 1 << '\n'; // correct way to calculate
                                                   // the value -9223372036854775808

#if __cpp_size_t_suffix >= 202011L // C++23
    static_assert(std::is_same_v<decltype(0UZ), std::size_t>);
    static_assert(std::is_same_v<decltype(0Z), std::make_signed_t<std::size_t>>);
#endif
}

출력:

123
83
291
2
12345678901234567890
12345678901234567890
9223372036854775808
-9223372036854775808

결함 보고 (Defect reports)

동작 변경 결함 보고로 size-suffix 가 있는 정수 리터럴이 확장 정수 타입을 가질 수 있었던 것을, 너무 크면 규칙 위반이 되도록 고쳤어요 (CWG 2698, C++23).

더 알아보기 (Learn more)