식별자의 첫 글자는 비숫자 문자를 사용할 수 있다. 비숫자 문자에는 영문 대소문자, 밑줄 문자 ('_')가 포함되며, C++11부터 다국어 문자도 포함된다.
첫 글자 이후의 문자는 비숫자 문자와 숫자를 사용할 수 있다.
표준에는 식별자 길이에 제한은 없다. 그러나 구현에 따라 식별에 사용되는 문자의 수가 정해지기도 한다.
특수문자는 식별자에 포함될 수 없다. 다만 MS 비주얼 C++에서는 '$'를 사용할 수 있다.
키워드는 식별자로 사용이 불가하다.
auto 키워드
변수를 선언할 때는 그 변수가 저장할 값의 타입(자료형)을 지정해야 한다.
C++11의 자료형 추론을 활용하면 변수를 초기화하는 값의 타입에 맞게 변수를 선언할 수 있다.
자료형 추론은 auto 키워드를 사용한다.
auto i{10}; // int i{10}; 과 동일
const 키워드
변수의 값이 항상 고정된 값을 갖게 하려면 변수를 선언할 때 const라는 키워드를 사용한다.
const double PI{3.14159};
const 키워드로 지정된 저장 영역은 값을 수정할 수 없다.
#define 전처리 지시어를 사용하여 매크로 상수를 정의하는 것도 하나의 방법이 될 수 있지만 매크로 상수를 사용하는 것은 해당 값의 리터럴을 직접 사용하는 것과 같으므로 이에 대한 참조나 포인터를 사용할 수 없다. 따라서 C++에서는 const 키워드를 사용하는 것이 일반적이다.
constexpr 키워드
constexpr 키워드는 그 값을 컴파일할 때 평가하라는 의미이다.
이것은 실행 중(런타임)에 값을 평가하는 것에 비해 효율적으로 동작할 수 있다.
int a;
std::cin >> a;
const int b = 20;
const int c = a;
constexpr int D1 = a + 10; // ERROR: 컴파일 타임에 a값이 확정되지 않아 알 수 없다
constexpr int D2 = b + 100; // OK: 컴파일 타임에 b값을 알 수 있기 때문에 가능
constexpr int D3 = c*3; // ERROR: 컴파일 타임에 a값이 확정되지 않아 c값도 알 수 X
함수도 constexpr 키워드로 선언(구현)할 수 있다. 모든 인수가 constexpr 특징을 갖는 경우 컴파일 타임에 값을 구할 수 있게 하라는 의미이다.
constexpr fac(int n) { return n > 1 ? n*f(n-1) : 1; }
void f(int x){
constexpr int a = fac(4); // 컴파일 타임 때 결정될 수 있기 때문에 컴파일 시에 계산 O
int b = fac(x) // 인수가 constexpr하지 않다 => 실행 중 계산
}
타입과 변수 정의
기본 타입
기본 자료형이란 프로그래밍 언어에서 데이터를 표현하기 위한 기본적인 표현 형식이다.
C++의 기본 자료형은 고정소수점 표현 방식인 정수형 자료형과 부동소수점 표현 방식인 실수형 자료형으로 분류할 수 있다.
C++ 기본 타입
고정된 너비 정수
C++은 정수 변수가 특정 최소 크기를 가질 것을 보장하고, 시스템에 따라서 크기가 더 커질 수 있다.
정수 변수의 크기가 고정되어 있지 않은 이유: C는 컴파일러가 대상 컴퓨터 아키텍처에서 가장 잘 작동하는 int의 크기를 선택할 수 있도록 의도적으로 정수의 크기를 열어 두는 것을 선택했다. 그것을 그대로 C++도 계승한 것인데, 대상 아키텍처에 따라 크기가 달라질 수 있는 변수를 다루는 것은 좀 터무니없는 일이다.
크로스 플랫폼을 위해 C99에서는 모든 아키텍처에서 같은 크기를 갖도록 보장하는 고정 너비 정수(stdint.h)를 정의했다.
#include <iostream>
#include <cstdint>
int main()
{
std::int16_t i(5); // direct initialization
std::cout << i;
return 0;
}
int8_t와 uint8_t는 각각 char와 unsigned char와 같이 동작할 수 있지만 시스템에 따라 다르게 동작할 수도 있다 => int8_t와 uint8_t 사용은 자제
#include <iostream>
#include <cstdint>
int main(){
std::int_8t myInt = 65;
std::cout << myInt // 보통 'A'를 출력하겠지만 시스템에 따라 65가 출력될 수도 있다.
return 0;
}
부동 소수점 숫자
C++에는 float, double 및 long double 과 같은 부동 소수점 자료형이 있다.
정수와 마찬가지로 C++은 이러한 자료형의 크기를 지정하지 정의하지 않았다.
현대 아키텍처에서 부동 소수점 표현은 거의 항상 IEEE 754 바이너리 형식을 따른다. 이 형식에서 float은 4 byte이고 double은 8 byte이며 long double은 8, 12, 16 byte 중 하나다.
정밀도와 범위
부동 소수점 숫자는 특정 유효 자릿수까지만 저장하고 나머지는 손실된다.
부동 소수점의 정밀도(precision)는 정보 손실 없이 나타낼 수 있는 유의한 자릿수를 정의한다.
부동 소수점 숫자를 출력할 때 std::cout의 기본 정밀도는 6이다. 즉, 모든 부동 소수점 숫자는 6자리까지만 유의하다고 가정하여 이후는 잘라낸다.
#include <iostream>
int main()
{
float f;
f = 9.87654321f; // f suffix means this number should be treated as a float
std::cout << f << std::endl;
f = 987.654321f;
std::cout << f << std::endl;
f = 987654.321f;
std::cout << f << std::endl;
f = 9876543.21f;
std::cout << f << std::endl;
f = 0.0000987654321f;
std::cout << f << std::endl;
return 0;
}
output:
9.87654
987.654
987654
9.87654e+006
9.87654e-005
그러나 <iomanip> 헤더 파일에 정의된 std:setprecision() 함수를 사용해서 cout에서 출력되는 기본 정밀도를 재정의(override)할 수 있다.
#include <iostream>
#include <iomanip> // for std::setprecision()
int main()
{
std::cout << std::setprecision(16); // show 16 digits
float f = 3.33333333333333333333333333333333333333f;
std::cout << f << std::endl;
double d = 3.3333333333333333333333333333333333333;
std::cout << d << std::endl;
return 0;
}
output:
3.333333253860474
3.333333333333334
정밀도를 16자리로 설정했으므로 위의 각 숫자는 16자리로 출력된다. 하지만 그 숫자들이 16자리까지 모두 정확하지는 않다.
부동 소수점 자료형의 변수가 가지는 정밀도는 자릿수 크기('float은 double보다 작다.)와 저장되는 특정 값에 따라 달라진다.
float 값의 정밀도는 6 ~ 9 자리다.
double 값의 정밀도는 15 ~ 18 자리로 16
long double 은 얼마나 많은 바이트를 차지하느냐에 따라 최소 15, 18 또는 33의 자리 정밀도를 가진다.
정밀도 문제는 단지 소수점 이하의 숫자에만 영향을 미치는 것이 아니라, 너무 많은 유효 숫자에도 영향을 미친다. 큰 숫자를 고려해 보자.
#include <iostream>
#include <iomanip> // for std::setprecision()
int main()
{
float f(123456789.0f); // f has 10 significant digits
std::cout << std::setprecision(9); // to show 9 digits in f
std::cout << f << std::endl;
return 0;
}
Output:
123456792
123456792_는 123456789_보다 크다. 값 123456789.0_은 10자리 숫자이지만 float은 일반적으로 7자리 정밀도를 가지기 때문에 정밀도를 잃고, 예상하지 못한 결과가 출력된다.
따라서 변수가 보유 할 수가 있는 것보다 더 정밀도가 필요한 부동 소수점 숫자를 사용할 때는 주의해야 한다.
무한 시퀀스로 표현되는 소수
binaray(2진수)에서 0.1은 0.00011001100110011…와 같은 무한 시퀀스로 표현된다. 이 때문에 부동 소수점 숫자에 0.1을 지정하면 0.1은 두자리 실수임에도 정밀도 문제가 발생한다.
#include <iostream>
#include <iomanip> // for std::setprecision()
int main()
{
double d(0.1);
std::cout << d << std::endl; // use default cout precision of 6
std::setprecision(17);
std::cout << d << std::endl;
return 0;
}
This outputs:
0.1
0.10000000000000001 (: rounding error)
정밀도를 17로 설정했다. 메모리 제한으로 인해 무한 시퀀스에서 근사치를 잘라내야 했기 때문에 반올림이 발생하고 그 결과 수치는 정확하게 0.1이 아니다. 이를 반올림 오류(rounding error)라고 한다.