배움 저장소
[홍정모의 따라하며 배우는 C++] 2.변수와 기본적인 자료형 본문
2.1 기본 자료형 소개(Fundamental Data Types)
Fundamental types
- 자료형마다 저장공간이 정해져있다. 큰 저장공간을 사용하는데 이를 활용하지 않으면 낭비이다.
- 자료형은 필요에 맞게 사용함이 좋다.
character 문자
-이모티콘 같이 다양한 문자를 사용함에 따라 저장공간이 많은 char 자료형이 필요했다. 2byte, 4byte char 자료형이 있음을 확인할 수 있다.
-wchar_t는 windows 개발에 여럿 쓰인다. Linux- window간 호환성 문제가 생길 수 있어 잘 사용하지 않는 추세이다.
Integer 정수
- signed 보다 unsigned 연산이 빠를 때가 있다. 간단한 연산을 수없이 반복할 때 unsigned을 사용하면 유리하다.
- Italic 표시된 keyword는 생략할 수 있다
- char 자료형은 정수, 문자 모두 표기할 수 있다. 단 std::cout은 char 자료형을 문자로 취급한다.
float 실수
- float를 single precision, double을 double precision이라 부른다.
literal 실수 값을 입력할 때 float와 double은 어떻게 구분할까?
- float 값은 double과 구분하기위해 끝에 f를 붙여준다. f를 붙여주지 않으면 double 자료형으로 인식해 trancation이 발생한다(저장공간이 큰 자료형에서 저장공간이 좁은 자료형으로 데이터를 복사하여 데이터 손실이 일어남)
- 아래 코드에서 출력값이 반올림 되는 이유는 exponent * mantissa로 계산할 수 있는 값이 3.141592의 근사치이기 때문이다. 가까운 값을 할당해준다.
double d = 3.141592;
float f = 3.141592f; // float value needs 'f' at the end
cout << d << endl; // >> 3.14159
cout << f << endl; // >> 3.14159
void
- void type은 저장공간을 차지하지 않는다
- 함수의 매개변수가 없거나 반환값이 없을 때 사용한다
자료형이 메모리를 사용하고 있는 모습
- 8bit = 1byte
- char 자료형은 1byte를 사용하고 있다. int 자료형은 4byte를 사용하고 있다.
변수의 다양한 초기화 방법
- 이 때 입력값과 자료형이 일치하지 않으면 데이터 손실이 일어난다
int a = 1; // copy inialization
int b(2); // direct inialization
int c{ 3 }; // uniform inialziation
int A = 1.1; // Warning, conversion from double to int
int B(2.2); // Warning, conversion from double to int
int C{ 3.3 }; // Error!!! conversion from double to int
copy initialization과 direct initialization은 다른 자료형을 할당하면 자료형 변환(casting)을 해준다
uniform initalization은 자료형이 맞지 않으면 에러메시지를 출력한다
- 예제에서 double(8byte) 데이터를 int(4byte)로 변환하므로 데이터 손실이 나타난다.
int A = (int)1.1;
int B((int)2.2);
같은 자료형의 변수를 여럿 초기화 할 수 있다
int x = 2, y = 3, z = 4;
int X = 2, Y(3), Z{ 4 }; // Not recommend so messy.
2.2 정수형 (Integers)
Category | Type | 최소크기 | 기타 |
Character(문자) | char | 1 byte | 네트워크에서 분야에서 최소크기로 활발하게 사용 |
Integer(정수) | short | 2 byte | |
Int | 2 byte | 최소크기로 지정되어있으나 대부분 4byte | |
long | 4 byte | ||
long long | 8 byte | C99/C++11 type |
자료형의 최대값 최소값을 확인하는 standard library
- numeric_limits<type>::function( )을 활용하여 해당 자료형 정보를 확인해볼 수 있다.
#include <iostream>
#include <cmath> // pow( )
#include <limits> // numeric_limits
int main() {
using namespace std;
short s = 1;
cout << pow(2, sizeof(signed short) * 8 - 1) - 1 << endl;
// ^ ^
// 15bit( 1bit is for +/- ) Start from 0
cout << numeric_limits<short>::max() << endl;
cout << numeric_limits<short>::min() << endl; // float's min and lowest is diff
cout << numeric_limits<short>::lowest() << endl;
cout << SHRT_MAX << endl;
}
float 자료형의 min 값과 lowest 값은 다르다.
- numeric_limits에서 min( ) 값은 가장 작은 절대값을 반환한다. 음수 최소값은 lowest( )이 반환한다
cout << numeric_limits<float>::max() << endl; //>> 3.40282e+38
cout << numeric_limits<float>::min() << endl; //>> 1.17549e-38
cout << numeric_limits<float>::lowest() << endl; //>> - 3.40282e+38
정수 나누기 정수 결과값의 자료형은?
- 정수 / 정수 값은 정수 결과값이 나온다
- 서로 다른 자료형의 연산은 자료형을 일치시킨 다음 연산을 수행한다. 이 때 더 큰 자료형으로 일치시킨다.
cout << 22 / 4 << endl; // >> 5
cout << float(22) / 4 << endl; // >> 4.4
2.3 C++ 11 고정너비정수 (Fixed-width Integers)
컴파일러러 마다 자료형의 저장공간 크기가 다를 수 있다
- c++표준 Fundamental types는 각 자료형이 가져야할 최소한의 저장공간을 정의하였다. 제작자는 이를 따라 컴파일러를 제작한다.
- <cstdin>라이브러리에서 지원하는 자료형은 표준으로 정해져 있다.
- <cstdint> 내부에 정의된 자료형을 사용하여 multiplatform에서 실행가능한 프로그램을 만들 수 있다.
#include <iostream>
//#include <cstdint> // Fixed-width Integers
// iostream already including this
int main() {
std::int16_t i_two_byte(5);
std::int8_t i_one_byte(65); // this print out 'A' char
std::int_fast8_t i_one_byte_fastest(5);
std::int_least64_t i_least_eight_byte(5);
}
2.4 무치형 (보이드, Void)
- void 자료형을 사용하여 포인터 값을 저장할 수 있다. void 포인터는 dereference/indirect는 할 수 없다. 해당 자료형을 알고 있어야 해당 값을 어떻게 해석할지 알 수 있기 때문이다.
void variable_void; // Error! void doesn't take any memory
int i = 123;
float f = 123.12345f;
void* ptr;
ptr = (void*)&i; // possible
ptr = (void*)&f; // possible
2.5 부동소수점수 floating point numbers
Type | 최소크기 | 자주 차용되는 크기 |
float | 4 byte | 4 byte |
double | 8 byte | 8 byte |
long double | 8 byte | 8, 12, 16 byte |
Floating Point Numbers가 이진수로 표현되는 원리
- 이 때 지수부분에서 2^(7-127)을 보자. -127은 bias이다. 메모리에 저장되고 계산되는 규칙이 있다.
Scientific notation 'E'
- 큰 수를 다루는 과학에서 숫자를 쉽게 표기하기위하여 10의 지수를 E+1 형태로 사용한다.
cout << 3.14 << endl; // >> 3.14
cout << 31.4E-1 << endl; // >> 3.14
cout << 314E-2 << endl; // >> 3.14
<iomanip> Input output manipulator
- 입출력을 제어할 수 있는 라이브러리로, double 자료형의 precision을 더 자세하게 출력할 수 있다.
#include <iostream>
#include <iomanip> // input/output manipulator
int main() {
std::cout << 1.0 / 3.0 << std::endl; // >> 0.333333
std::cout << std::setprecision(16);// default is 6
std::cout << 1.0 / 3.0 << std::endl; // >> 0.3333333333333333
}
부동소수점 수는 지수+가수 형태로 숫자를 표현한다
- 표현할 수 있는 수가 정해져 있다. 따라서 입력값과 가장 가까운 수를 저장한다.
- setprecision으로 정확도를 정하면 해당 정확도 내에서 가장 가까운 수를 저장한다.
float f(123456789.0f); // 10 significant digits
cout << std::setprecision(9); // float give closest number
cout << f << endl; // >> 123456792
cout << std::setprecision(5);
cout << f << endl; // >> 1.2346e+08
부동소수점 수가 만드는 오차
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 << std::setprecision(17);
cout << d1 << endl; // >> 1
cout << d2 << endl; // >> 0.99999999999999989
// bias are accumulating
double 자료형이 만들어내는 오류값
- double 자료형은 infinite와 nan 값을 출력할 수 있다.
- <cmath> library에 있는 함수를 사용하여 double 자료형에 저장된 값이 오류값을 확인가능하다.
#include <iostream>
#include <cmath> // isinf, isnan
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)
// indeterminate
// How to prevent to get above example?
// use <cmath> library's function
cout << isinf<double>(posinf) << endl; // >> 1
cout << isinf<double>(neginf) << endl; // >> 1
cout << isnan<double>(nan) << endl; // >> 1
cout << isnan<double>(1.2) << endl; // >> 0
}
2.6 불리언 자료형과 조건문 if
Bool 자료형
bool b1 = true; // copy initialization
bool b2(true); // direct initialization
bool b3{ true }; // uniform initialization
//cout << std::noboolalpha; // set bool value's output is num
cout << std::boolalpha; // set bool value's output is string
cout << ! b1 << " " << b2 << " " << b3 << endl; // >> false true true
if 조건문
- if( expression )에서 expression 값이 0이면 false, 0이 아니면 true이다. 따라서 0이 아닌 어떤 값을 넣어도 true이다.
if(5)
{
// do sth..
}
2.7 문자형 char type
정수<->문자 형변환이 가능하다
char c1(65); // assign number but printing character
char c2('A');
cout << c1 << " " << c2 << endl; // >> A A
// C style casting
cout << (int)c1 << " " << (int)c2 << endl; // >> 65 65
// C++ style
cout << int(c1) << " " << int(c2) << endl; // >> 65 65
cout << char(65) << endl; // >> A
cout << int('A') << endl; // >> 65
std::endl VS '\n'
- 입력/출력 값이 어마어마하게 클 때 '\n'문자가 버퍼에 남아 출력되지 않는 경우가 생긴다. 이때 std::endl이 유용하다.
' \n ' : 단순히 줄바꿈 문자를 출력한다.
std::endl : std::cout에서 사용하는 buffer에 있는 값을 모두 출력시킨다. 이후 줄바꿈 문자를 출력한다.
참고) std::flush를 사용하면 buffer에 있는 값을 모두 출력시킨다. 줄바꿈 문자는 없다.
2.8 리터럴 상수 literal constants
quatation mark( ' )를 사용하면 숫자를 읽기 쉽게 표기할 수 있다. Compiler는 이를 무시한다.
/* suffix of literal number */
unsigned int ui = 5u;
long li = 5'000'000L; // ' is neglected by compiler
double d = 1234.5678E-4;
/* Binary */
int binary = 0b0000'0101; // 1 + 4 = 5
/* Octal */
int oct = 012; // 8 + 2 = 10
/* Hex */
int hex = 0x12; // 16 + 2 = 18
2.9 심볼릭 상수 symbolic constants
Symbolic constant: Identifier(식별자) 또는 이름을 가진 고정 값이다. const keyword를 사용한다.
함수의 Parameter(매개변수)에 자주 사용한다.
compile time constant와 runtime constant
- 상수는 compile time 혹은 run time에 결정되어야 한다. C와 다르게 run time 상수를 허용한다
const int compile_time_constant(100);
int number;
cin >> number;
const int runtime_constant(number);
constexpr Keyword in C++17
- constant 상수가 compile time에 초기화 되었는지 확인하는 keyword이다.
- constexpr keyword가 붙은 변수가 runtime에 초기화되면 Error를 발생시킨다.
constexpr int only_compile_constant(-100);
// ^ this check whether inited at compile time
constexpr int error_runtime_constant(number); // Error!
C style Macro는 C++에서 쓰지 않는다. constant를 사용하자
- #define Macro는 저장공간을 차지하지 않아 디버깅이 힘들다.
- Scope가 너무 넓다. File Scope라 사용하지 않는 곳에서도 존재한다.
const 변수는 header 파일 내 namespace에서 묶어놓으면 쓰기쉽다
- 상수 값을 변경할 때 편리하다. header -> namespace에서 해당 상수 값을 바꾸면 모든 파일에 적용된다.
// constants.h
namespace constants
{
constexpr double pi(3.141592);
constexpr double gravity(9.8);
}
// main.cpp
#include <iostream>
#include "constants.h"
int main()
{
double radius;
std::cin >> radius;
double circle = radius * radius * constants::pi;
}
'Programming Language > C++' 카테고리의 다른 글
[홍정모의 따라하며 배우는 C++] 4.변수 범위와 더 다양한 변수형 (0) | 2021.12.15 |
---|---|
[홍정모의 따라하며 배우는 C++] 3. 연산자들 (0) | 2021.12.14 |
[홍정모의 따라하며 배우는 C++] 1.C++의 기초적인 사용법 (0) | 2021.12.11 |
[홍정모의 따라하며 배우는 C++] 0. 시작해봅시다. (0) | 2021.12.10 |
[C++] Template (0) | 2021.11.13 |