02.09 - 리터럴 (literal)
C++에는 두 가지 상수(constant)가 있다: 리터럴(literal), 심볼릭(symbolic)
리터럴 상수(Literal constant)
리터럴(literal)은 코드에 직접 삽입된 값이다. 이 값은 변경할 수 없으므로 '상수'다.
bool myBlogIsBoy = true;
int x = 5;
std::cout << 2 * 3;
정수와 부울 리터럴은 간단하지만, 부동 소수점 리터럴을 선언하는 방법은 두 가지가 있다.
double pi = 3.14159;
double avogadro = 6.02e23;
두 번째 형식에서 지수 뒤의 숫자가 음수일 수도 있다.
double electron = 1.6e-19;
숫자 리터럴에서는 유형을 결정하는 접미사가 포함될 수 있다. 이 접미사는 선택사항으로 생략하면 컴파일러는 의도하는 것이 어떤 종류의 상수인지 유추한다.
Data Type |
Suffix |
Meaning |
int |
u or U |
unsigned int |
int |
l or L |
long |
int |
ul, uL, Ul, UL, lu, lU, Lu, or LU |
unsigned long |
int |
ll or LL |
long long |
int |
ull, uLL, Ull, ULL, llu, llU, LLu, or LLU |
unsigned long long |
double |
f or F |
float |
double |
l or L |
long double |
예제:
unsigned int nValue = 5u;
long nValue2 = 5L;
float fValue = 5.0f;
double d = 6.02e23;
C++은 문자와 문자열 리터럴도 제공한다.
char c = 'A';
std::cout << "Hello, world!"
std::cout << "Hello," " world!"
8진수와 16진수 리터럴 (Octal and hexadecimal literals)
일상생활에서 우리는 보통 10진법decimal)으로 숫자를 센다. 각 숫자는 0, 1, 2, 3, 4, 5, 6, 7, 8, 9가 된다. 10진수는 가능한 10자리 숫자(0~9)가 있으므로 "base10"이라고도 불린다. 일반적으로 C++에서 숫자는 10진수로 간주한다.
int x = 12;
2진법(binary)는 0과 1 두 수만 있으므로 "base2"라고 한다. (ex. 0, 1, 10, 100, 101, 110, 111)
8진법(octal)과 16진법(hexadecimal)도 있다.
8진법은 "base8"이다. 즉, 사용할 수 있는 순자는 0, 1, 2, 3, 4, 5, 6, 7이다. 10진법과 비교하면 다음과 같다.
10진법 (Decimal)
| 0
| 1
| 2
| 3
| 4
| 5
| 6
| 7
| 8
| 9
| 10
| 11
|
8진법(Octal) |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
8진수 리터럴을 사용하려면, 리터럴 앞에 0
을 붙이면 된다.
#include <iostream>
int main()
{
int x = 012;
std::cout << x;
return 0;
}
This outputs:
10
왜 12가 아닌 10이 출력되었을까? 왜냐하면, 숫자는 10진수로 출력되어 있고 8진수 12는 10진수 10과 같기 때문이다. 8진법은 어려우므로 사용을 피하는 게 좋다.
16진법(hexadecimal)은 "base16"이다. 숫자는 다음과 같이 센다: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12 ...
10진법(Decimal)
| 0
| 1
| 2
| 3
| 4
| 5
| 6
| 7
| 8
| 9
| 10
| 11
| 12
| 13
| 14
| 15
| 16
| 17
|
16진법(Hexadecimal) |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
A |
B |
C |
D |
E |
F |
10 |
11 |
8진수 리터럴을 사용하려면, 리터럴 앞에 0x
를 붙이면 된다.
#include <iostream>
int main()
{
int x = 0xF;
std::cout << x;
return 0;
}
This outputs:
15
16진수가 사용 가능한 숫자는 16개가 있으므로 하나의 16진수 숫자는 4-bit다. 그러므로 16진수를 사용해서 전체 byte를 나타낼 수 있다.
32비트 정수 값 '0011 1010 0111 1111 1001 1000 0010 0110'을 보자. 숫자의 길이 때문에 읽기 쉽지 않다. 16진수에서 동일 값은 '3A7F 9826'이다. 이처럼 16진수는 메모리의 값을 간결하게 표현할 때 유용하다. 그래서 16진수는 메모리 주소 또는 메모리의 값을 표현할 때 자주 사용한다.
C++ 14 이전에는 이진 리터럴(binary literal)을 할당할 수 없었으므로 16진수를 이용해 할당했다.
int main()
{
int bin(0);
bin = 0x01
bin = 0x02
bin = 0x04
bin = 0x08
bin = 0x10
bin = 0x20
bin = 0x40
bin = 0x80
bin = 0xFF
bin = 0xB3
bin = 0xF770
return 0
}
C++ 14의 이진 리터럴과 숫자 구분 기호 (C++14 binary literals and digit separators)
C++ 14에서는 0b
접두사를 사용해서 이진 리터럴을 할당할 수 있다.
#include <iostream>
int main()
{
int bin(0);
bin = 0b1; // assign binary 0000 0001 to the variable
bin = 0b11; // assign binary 0000 0011 to the variable
bin = 0b1010; // assign binary 0000 1010 to the variable
bin = 0b11110000; // assign binary 1111 0000 to the variable
return 0;
}
긴 리터럴은 읽기 어려우므로 C++ 14는 숫자 구분 기호로 따옴표(')를 사용할 수 있다.
#include <iostream>
int main()
{
int bin = 0b1011'0010; // assign binary 1011 0010 to the variable
long value = 2'132'673'462; // much easier to read than 2132673462
return 0;
}
매직 넘버와 안좋은 이유 (Magic numbers, and why they are bad)
int maxStudents = numClassrooms * 30;
위 코드에서 30과 같은 숫자를 매직 넘버(magic number)라고 부른다. 매직 넘버란 컨텍스트(context)가 없는 코드 중간에서 하드 코딩된 리터럴(일반적으로 숫자)을 말한다. 여기서 30은 교실당 최대 학생 수를 의미한다는 것을 유추해야 한다. 30을 설명하기 위한 주석이 없으면 나중에 추론하는 게 매우 어려울 수 있다.
매직 넘버를 사용하는 것은 나쁜 습관인데, 매직 넘버가 무엇에 사용되는지에 대한 컨텍스트(context)가 없을뿐더러 나중에 값을 바꿔야 할 경우 문제가 발생하기 때문이다.
int maxStudents = numClassrooms * 30
setMax(30)
교실의 크기가 커져서 교실당 학생 수가 35명이 되었다고 가정해보자. 상수 30을 35로 수정해야 한다. 그런데 setMax()
함수의 인자로 들어가는 30도 35로 수정해야 할까? 같은 의미라면 수정해야 하고 그렇지 않다면 내버려 두어야 한다. '전역 검색→바꾸기' 와 같은 에디터의 기능을 수행하면 변경하지 말아야 할 setMax()
함수의 인자를 수정할 수도 있다. 이와 같은 문제를 방지하려면 리터럴 30의 모든 인스턴스에 대한 코드를 살펴봐야 한다. 이는 심각한 시간 낭비다.
매직 넘버를 사용하지 말자.
번역: 이 포스트의 원문은 http://www.learncpp.com/cpp-tutorial/28-literals/ 입니다.