2.1 기본 자료형 소개
* 1 byte = 8 bits
| Group | Type names | Notes on size /precision |
| Character types | char | Exactly one byte in size. At least 8 bits. |
| char16_t | Not smaller than char. At least 16 bits. | |
| char32_t | Not smaller than char16_t. At least 32 bits. | |
| wchar_t | Can represent the largest supported character set. | |
| Integer types (signed) | signed char | Same size as char. At least 8 bits. |
| signed short int | Not smaller than char. At least 16 bits. | |
| signed int | Not smaller than short. At least 16 bits. 대부분 4 btytes |
|
| signed long int | Not smaller than int. At least 32 bits. | |
| signed long long int | Not smaller than long. At least 64 bits. | |
| Integer types (unsigned) | unsigned char | (same size as their signed counterparts) |
| unsigned short int | ||
| unsigned int | ||
| unsigned long int | ||
| unsigned long long int | ||
| Floating-point types | float | |
| double | Precision not less than float | |
| long double | Precision not less than double | |
| Boolean type | bool | |
| Void type | void | no storage |
| Null pointer | decltype(nullptr) |
https://cplusplus.com/doc/tutorial/variables/
* (Signed) int는 음의 정수, 0, 양의 정수(자연수)를, unsigned int는 양의 정수와 0을 포함한다.
* Signed와 Unsigned는 저장되는 방식이 달라서 Unsigned가 특정 연산을 할 때는 더 빠르다.
float fValue = 3.141592f; // float는 끝에 f를 붙여줘야 float로 인식한다.
double dValue = 3.141592;
auto aValue = 3.141592;
auto aValue2 = 3.141592f;
cout << fValue << endl;
cout << dValue << endl;
int a(123); // direct initialization
int b{ 123 }; // uniform initialization
int c = 123; // copy initialization
int a1(3.14); // warning
int b2{ 3.14 }; // error
* uniform initialization이 더 엄격하다.
2.2 정수형
00000000 00000000 00000000 00000001
int형은 4 bytes = 32 bits
1 bit에는 0과 1 두가지로 구분이 되므로 총 2^32개의 숫자를 표현할 수 있다.
* 맨 처음 비트는 부호에 사용
short s = 1;
int i = 1;
long l = 1;
long long ll = 1;
cout << sizeof(short) << endl; // 2 = 2^16 가짓수
cout << sizeof(int) << endl; // 4 = 2^32 가짓수
cout << sizeof(long) << endl; // 4 = 2^32 가짓수
cout << sizeof(long long) << endl; // 8 = 2^64 가짓수
오버플로우 (overflow)
#include <iostream>
#include <cmath>
#include <limits>
using namespace std;
int main()
{
short s = 1; // 2 bytes = 16 bits
cout << std::pow(2, sizeof(short) * 8 - 1) - 1 << endl; // 32767 : 표현할 수 있는 가장 큰 숫자
cout << std::numeric_limits<short>::max() << endl; // 32767 : 표현할 수 있는 가장 큰 숫자
cout << std::numeric_limits<short>::min() << endl; // -32768 : 표현할 수 있는 가장 작은 숫자
cout << std::numeric_limits<short>::lowest() << endl; // -32768
s = 32767;
s += 1;
cout << s << endl; // -32768 : overflow
s = -32768;
s -= 1;
cout << s << endl; // 32767 : overflow
return 0;
}
short가 표현할 수 있는 가장 큰 숫자는 32767이다.
그런데 32767에 1을 더하면 32768이 나오지 않고 -32768이 나온다.
표현할 수 있는 숫자를 넘어가서, 2진수로 표현할 때 가장 작은 수가 되는 것이다.
이런 것을 오버플로우라고 한다.
* 다른 데이터 타입에서도 오버플로우 발생 테스트 해보기 *
int, long, long long, unsigned short, unsigned int
cf) unsigned int에 -1을 넣으면 오버플로우가 발생한다.
unsigned int i = -1;
cout << i << endl; // 4294967295
2.3 고정 너비 정수
어떤 플랫폼이든지 똑같은 데이터 사이즈를 사용하는 것
#include <iostream>
using namespace std;
int main()
{
std::int16_t i(5); // 해당 플랫폼에서 16bit = 2byte 짜리 데이터 타입으로 바꾼다.
std::int8_t myint = 65;
cout << myint << endl; // A
std::int_fast8_t fi(5);
std::int_least64_t fl(5);
return 0;
}
int16_t : 해당 플랫폼에서 16bit = 2byte 짜리 데이터 타입으로 바꾼다.
int8_t는 1byte이므로 char 형으로 처리가 된다. 따라서 위 예제에서 변수 myint의 값 65는 char로 처리가 되어 A를 출력하게 되는 것이다.
fast8_t : 8bit 데이터 타입 중 가장 빠른 것
least64_t : 적어도 8byte를 갖는 데이터 타입
2.4 무치형 (Void)
void는 함수를 선언할 때 타입이 없다는 뜻으로 사용한다. 즉, 리턴타입이 없을 때 사용한다.
void는 메모리를 차지하지 않는다.
int main()
{
int i = 123;
float f = 123.456f;
void* my_void;
my_void = (void*)&i; // i의 주소
my_void = (void*)&f; // f의 주소
return 0;
}
데이터 타입이 다르고, 데이터 타입의 사이즈가 다르더라도 주소의 데이터 사이즈는 동일하다.
따라서 void로 형변환하여 변수의 주소값을 담을 수 있다.
2.5 부동소수점 수
컴퓨터는 실수를 다루기 위해 부동소수점 수(Floating Point Numbers)를 이용한다.
| Category | Type | 최소 크기 | 전형적인 크기 |
| 부동소수점 | float | 4 바이트 | 4 바이트 |
| double | 8 바이트 | 8 바이트 | |
| long double | 8 바이트 | 8, 12, 16 바이트 |
최근에 나오는 언어들은 double을 기본으로 사용한다. 하지만 float에 비해 double은 사이즈가 2배이기 때문에, 컴퓨터의 연산 속도나 메모리에 부담이 될 수 있다. 숫자를 많이 다루는 경우에는 float를 많이 사용한다. 예로, 딥러닝 같은 경우에는 GPU 계산을 할 때 float 위주로 작업된다.
부동소수점의 한계때문에 사용 시 주의가 필요하다.
#include <iostream>
#include <iomanip>
#include <limits>
using namespace std;
int main()
{
float f;
double d;
long double ld;
cout << sizeof(f) << endl; // 4 sizeof(float)와 동일하다.
cout << sizeof(d) << endl; // 8
cout << sizeof(ld) << endl; // 8
cout << numeric_limits<float>::max() << endl; // 3.40282e+38
cout << numeric_limits<double>::max() << endl; // 1.79769e+308
cout << numeric_limits<long double>::max() << endl; // 1.79769e+308
cout << numeric_limits<float>::min() << endl; // 1.17549e-38
cout << numeric_limits<double>::min() << endl; // 2.22507e-308
cout << numeric_limits<long double>::min() << endl; // 2.22507e-308
cout << numeric_limits<float>::lowest() << endl; // -3.40282e+38
cout << numeric_limits<double>::lowest() << endl; // -1.79769e+308
cout << numeric_limits<long double>::lowest() << endl; // -1.79769e+308
return 0;
}
* min은 표현할 수 있는 가장 작은 값의 절대값을 리턴한다. 최소값을 알고 싶으면 lowest()를 이용한다.
cout << 3.14 << endl;
cout << 31.4e-1 << endl; // 3.14 = 3.14 * 10^-1
cout << 31.4e-2 << endl; // 0.314 = 31.4 * 10^-2
cout << 31.4e1 << endl; // 314 = 31.4 * 10^1
cout << 31.4e2 << endl; // 3140 = 31.4 * 10^2
cout << 1.0 / 3.0 << endl; // 0.333333
cout << setprecision(16);
cout << 1.0 / 3.0 << endl; // 0.3333333333333333
float f(123456789.0f); // 10 significant digits
cout << setprecision(9);
cout << f << endl; // 123456792
double d(0.1);
cout << d << endl; // 0.1
cout << setprecision(17);
cout << d << endl; // 0.10000000000000001
double d1(1.0);
double d2(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1);
cout << d1 << endl; // 1
cout << d2 << endl; // 0.99999999999999989
// 부동소수점 오차의 누적
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double zero = 0.0;
double posinf = 5.0 / zero;
double neginf = -5.0 / zero;
double nan = zero / zero;
cout << posinf << endl; // inf
cout << neginf << endl; // -inf
cout << nan << endl; // -nan(ind)
cout << isnan(nan) << endl; // 1
cout << isnan(1.0) << endl; // 0
cout << isinf(posinf) << endl; // 1
cout << isinf(neginf) << endl; // 1
return 0;
}
* isnan : nan인지 확인하는 함수 (include cmath)
* isinf : inf인지 확인하는 함수 (include cmath)
2.6 Boolean 자료형과 조건문 if
Boolean 자료형은 조건을 판단할 때 많이 사용한다.
Boolean 자료형이 가질 수 있는 값은 true(1), false(0) 두 가지 뿐이다.
#include <iostream>
using namespace std;
int main()
{
bool b1 = true; // copy initialization
bool b2(false); // direct initialization
bool b3{ true }; // uniform initialization
b3 = false;
cout << std::noboolalpha;
cout << b3 << endl; // 0
cout << b1 << endl; // 1
cout << std::boolalpha;
cout << b3 << endl; // false
cout << b1 << endl; // true
// not operator
cout << !true << endl; // false
cout << !false << endl; // true
cout << (true && true) << endl; // true
cout << (true && false) << endl; // false
cout << (false && true) << endl; // false
cout << (false && false) << endl; // false
cout << (true || true) << endl; // true
cout << (true || false) << endl; // true
cout << (false || true) << endl; // true
cout << (false || false) << endl; // false
return 0;
}
2.7 문자형 char
#include <iostream>
using namespace std;
int main()
{
char c1(65);
char c2('A');
cout << c1 << " " << c2 << " " << int(c1) << " " << int(c2) << endl; // A A 65 65
return 0;
}
* c-style casting
cout << (char)65 << endl;
cout << (int)'A' << endl;
* c++ stlye casting
cout << char(65) << endl;
cout << int('A') << endl;
* 컴파일러에 casting이 문제 없는지 확인하는 과정을 거친다.
cout << static_cast<char>(65) << endl;
cout << static_cast<int>('A') << endl;
#include <iostream>
using namespace std;
int main()
{
char c1(65);
cin >> c1;
cout << c1 << " " << static_cast<int>(c1) << endl;
cin >> c1;
cout << c1 << " " << static_cast<int>(c1) << endl;
return 0;
}
위 코드에서 abc를 입력하면, 처음 cin에선 c1이 char형이기 때문에 a만 처리된다. 그리고 나머지 bc는 버퍼에 저장되어 있다가 두번째 cin에서 b가 처리된다.
#include <iostream>
using namespace std;
int main()
{
char c1(65);
cout << sizeof(char) << endl; // 1
cout << (int)numeric_limits<char>::max() << endl; // 127
cout << (int)numeric_limits<char>::lowest() << endl; // -128
cout << sizeof(unsigned char) << endl; // 1
cout << (int)numeric_limits<unsigned char>::max() << endl; // 255
cout << (int)numeric_limits<unsigned char>::lowest() << endl; // 0
return 0;
}
\n : new line
\t : tab
* endl과 \n의 차이
endl은 버퍼에 있는걸 무조건 화면에 출력하고 줄을 바꾼다. 하지만 \n은 버퍼에 남아있을 수 있다.
std::flush는 버퍼에 있는걸 출력하고 줄을 바꾸지 않는다.
wchar_t c;
char32_t c3;
2.8 리터럴 상수 (Literal Constants)
float pi = 3.14f;
unsigned int n = 5u;
long n2 = 5L;
double d = 6.0e-10;
* float는 초기화 변수 끝에 f를 붙여 준다. f를 붙이지 않으면 double로 인식한다.
float pi = 3.14;
이렇게 선언하면 3.14가 double에서 float로 casting 되어 pi에 저장된다.
* Decimal (10진수) : 0 1 2 3 4 5 6 7 8 9 10
* Octal (8진수) : 0 1 2 3 4 5 6 7 10 11 12 13
* Hexa (16진수) : 0 1 2 3 4 5 6 7 8 9 A B C D E F 10
int x1 = 012; // 8진수의 표현 -> 앞에 0 붙인다.
cout << x1 << endl; // 10
int x2 = 0xF; // 16진수의 표현 -> 앞에 0x 붙인다.
cout << x2 << endl; // 15
int x3 = 0b1010; // 2진수의 표현 -> 앞에 0b 붙인다.: c++14부터 가능하다.
cout << x3 << endl; // 10
int x4 = 100'000'000; // c++14부터 숫자 사이에 입력된 '는 컴파일러가 무시한다. 수를 구분하기 위해 사용하면 유용하다.
cout << x4 << endl;
* magic number 대신 const로 선언해서 사용하는게 좋다.
2.9 심볼릭 상수 (Symbolic constants)
const double gravity{ 9.8 }; // gravity 값을 바꿀 수 없는 상수로 지정한다.
const는 고정된 숫자로 만들 때 사용한다.
상수는 값이 정해지면 바꿀 수 없기 때문에 반드시 초기화를 해줘야 한다.
#include <iostream>
using namespace std;
// 파라미터로 전달된 값은 바꿀 필요가 없으므로 const를 붙여서 선언한다.
void printNumber(const int my_number)
{
int n = my_number; // 만약 바꾸려면 새로운 변수에 넣어서 사용한다.
cout << n << endl;
}
int main()
{
printNumber(123);
return 0;
}
int number;
cin >> number;
const int my_const(123);
const int special_number(number);
// number는 바꿀 수 있지만, special_number는 못 바꾼다.
// my_const는 컴파일 시 정해진다. (컴파일 상수)
// special_number는 실행을 해 봐야 알 수 있다. (런타임 상수)
constexpr int my_const2(1234); // 컴파일 시 결정되는 상수임을 명시한다.
constexpr int special_number2(number); // error
* define는 지양한다. 적용 범위가 너무 넓어서 디버깅이 힘들기 때문에. const를 사용하기로 한다.
const가 여기저기 있으면 헷갈리기 때문에 따로 모아 놓고 사용한다.
// MY_CONSTANTS.h
namespace constants
{
constexpr double pi(3.141592);
constexpr float gravity(9.8);
}
#include <iostream>
#include "MY_CONSTANTS.h"
int main()
{
double a = 2 * constants::pi;
return 0;
}'C, C++, MFC > 따배C++' 카테고리의 다른 글
| 섹션 1 - C++의 기초적인 사용법 (0) | 2024.07.01 |
|---|---|
| 섹션 0 - 시작해봅시다 (0) | 2024.02.13 |