C++ 공부에 앞서
우리가 C++을 공부하기 이전에 어셈블리에 대해 포스팅하고 공부했다. 그게 왜 중요했는지 잠깐이나마 얘기한다.
#include <iostream>
int main()
{
std::cout << "Hello World!\n";
}
VSC에서 프로젝트를 맨 처음 실행하면 생성되는 기본적인 코드이다. std::cout << "Hello World!\n"; 에 브레이킹 포인트를 잡고 디버그를 한 후, 디스어셈블리 창을 띄우면 다음과 같이 나오는걸 확인 할 수있다.
한줄 짜리 코드이지만, 그 안에 기계어는 많이 있는 것을 확인할 수 있다. 우리가 이전에 배웠던 stack이나 mov, xor 등 어떤 원리로 이루어져있는지 볼 수 있으므로 공부를 하면서 low 하게 봐야할 때 참고하면 좋다.
정수
프로그래밍을 단순하게 생각하면 적절한 데이터를 저장하고 가공하는 것이다. 데이터를 적절한 로직으로 버무리면 그것이 프로그램이 되는것이다. 그 중에서도 가장 빈번하게 사용되는 정수에 대해 알아보자.
일단 변수의 선언 방법은 어셈블리랑 크게 다르지 않다.
[타입] [이름];
[타입] [이름] = [초기값];
으로 선언할 수 있다.
먼저 int hp = 100; 이라고 선언해보자. 0이 아닌 초기화 값이 있기 때문에 이 변수는 .data 영역에 포함이 될것이다. 초기값이 0이거나, 초기값이 없는 변수였다면 .bss 영역에 포함이 될것이다.
그렇다면 int는 무엇인가?
정수를 나타내기 위한 키워드는 크게 4개로 볼 수 있다.
- char a; => 1 바이트 (-128 ~ 127)
- short b; => 2 바이트 (-32768 ~ 32767)
- int c; => 4 바이트 (-21.4억 ~ 21.4억)
- __int64 d; => 8 바이트(long long으로 쓰기도 함.) 어마어마 하게 큰 숫자
우리가 대부분 정수를 사용한다고 하면 int 타입을 떠올리고 사용한다.
그리고 타입을 선언할 때 signed는 생략되며 선언이 된다. 즉, 부호가 있다는 의미다.
하지만 반대로 unsigned를 사용하게 되면 부호가 사라진 양수가 되기 때문에 범위가 넒어진다.
- unsigned char a;
- unsigned short b;
- unsigned int c;
- unsigned __int64 d;
범위는 스스로 생각해보자.
자 그럼 여기서 든 생각은 귀찮은데 그냥 다 int로 4바이트로 설정하면 웬만한건 다 되는거 아니야?? 라고 생각이 든다.
그러나 콘솔이나 모바일 게임 같은 경우는 항상 메모리가 부족하다. pc랑 다르게 한정된 자원안에서 해결 해야하기 때문에 메모리를 관리하기 위해서라도 줄일 수 있는건 다 줄여야한다.
또 만약 온라인 게임이라고 해보자. 만약 내가 hp를 __int64로 설정했다고 하고 현재 내 hp가 10만이라고 해보자. 그러면 서버한테 내 hp를 전송해야하는데 전송, 수신 할때 마다 4바이트씩 손해를 본다. 4바이트가 얼마나 크다고 라고 생각하면 안된다. 이는 온라인 게임이기 때문에 모든 동접자가 1초에 수백번 패킷을 보낼텐데 그때마다 4바이트씩 손해를 본다는건 말이되지 않는다.
즉, 어떤 데이터를 정할 때 , 범위를 설정하는 것은 매우 중요하다.
#include <iostream>
using namespace std;
//변수 선언 방법
// [타입] [이름];
// [타입] [이름] = [초기값];
//0이 아닌 초기화 값이 있으면 .data 영역
int hp = 100;
char a; // 1바이트 (-128 ~ 127)
short b; // 2바이트 (-32768 ~ 32767)
int c; // 4바이트 (-21.4억 ~ 21.4억)
__int64 d; // 8바이트(long long)...어마어마하게 크다
unsigned char a; // 1바이트 (0 ~ 255)
unsigned short b; // 2바이트 (0 ~ 65536)
unsigned int c; // 4바이트 (0 ~ 42.9억)
unsigned __int64 d; // 8바이트(long long)...어마어마하게 크다
// 초기값이 0 이거나, 초기값이 없는 변수라면 .bss영역
//귀찮은데 그냥 다 int로 4바이트로 가면 안될까?
// -> 콘솔/모바일 게임 -> 메모리가 늘 부족하다
// -> 온라인 게임 -> 4바이트 * 1만명 손해
int main()
{
cout << "체력이 " << hp << " 남았습니다" << endl;
}
불리언(boolean)
통칭 bool 은 참과 거짓을 의미한다.
bool isHighLevel = true;
bool isPlayer = true;
bool isMale = false;
이런 식으로 특정 값이 진실이냐 거짓이냐로 나눌 수 있을 때, 선언하여 사용하는 타입으로 매우 유용하다.
사실 bool은 그냥 1 바이트의 정수에 불과하다. 어셈블리에서도 bool 이라는 것은 없다. 심지어 남자인지 판단하기 위해 bool isMale = true; 이 아닌 int isMale =1;로 하여 1이면 남자, 0 이면 여자로 표기해도 상관 없다.
그렇다면 bool이라는 자료형을 왜 만들어 둔것일까?
이는 가독성의 문제이다. int 형으로 참과 거짓을 나누는 것보다 bool 이라는 것으로 true false를 나누는게 프로그래머 입장에서 코드를 읽을 때 유용하다.
부동소수점(실수)
정수 뿐만 아니라 만약 소수점을 가진 변수를 만들고 싶을 땐 어떡할까?
flaot 와 double이 있다.
float attackSpeed = 0.539f //4바이트
double attackSpeed2 = 123.12415 // 8바이트
int 형은 비트로 표현하기 정말 쉬운데 실수는 어떻게 표현할까? 바로 부동소수점으로 표현하는 방법이다.
가령 예를 들어. 3.1415926535 = 0.31415926535 * 10 = 0.031415926535 * 10^2 로 전부 같은 말이다.
이 것을 먼저 정규화 한다. (0.31415926535 * 10 등으로) 그리고 유효 숫자와 지수를 추출한다. 여기서 유효 숫자는 31415926535이고 지수는 1이다. 이것을 가지고 비트로 표현해 저장한다
float 같은 경우 부호 1비트 지수 8비트 유효숫자 23비트로 총 32비트인 4바이트로 표현하고
double 같은 경우 부호 1비트 지수 11비트 유효숫자 52비트로 총 64비트인 8바이트로 표현한다.
주요할 점은 프로그래밍 할 때 부동소수점은 항상 '근사값'이라는 것을 기억해야한다.
즉 특히 수가 커질 수록 오차 범위도 매우 커진다.
그러니 실수 2개를 == 으로 비교하는(나중에 배움) 것은 위험하다. 오차를 어느정도 계산해야한다.
문자
bool은 그냥 정수지만 참과 거짓을 나타내기 위해 사용한다고 위에서 말했다. 사실 char 등 문자도 마찬가지이다. 그냥 정수지만 '문자' 의미를 나타내기 위해 사용한다.
- char : 알파벳/ 숫자 문자를 나타낸다
- wchar_t : 유니코드 문자를 나타낸다.
#include <iostream>
using namespace std;
char test = 97;
int main()
{
cout << test << endl;
}
이런 코드를 작성해보자. 예상 결과는 97이 나와야한다.
하지만 결과는 a가 나왔다. 이는 아스키 코드로 인해 97이라는 숫자가 알파벳 a로 변환된 것이다. 일반적으로는 char형은 문자로 사용하는 것이다.
그렇기에 문자의 의미로 작은 따옴표를 사용하기도 한다.
char = 'a';
char = '1'; // 1이라는 값이 들어가는게 아니라 아스키 코드에서 1을 가르키는 정수가 들어간다
하지만 영어만 되는것인가??? 국제화 시대에는 영어만으로 서비스 할 수 없다. 전 세계 모든 문자에 대해 유일 코드를 부여한 것이 유니코드(unicode)이다.
유니코드에서 가장 많은 번호를 차지하는 것은 한국어/ 중국어이다. 그 이유는 우리나라 언어는 특이한 단어 뷁 웱 등 모든걸 표현할 수 있기 때문이다.
유니코드는 표기 방식이 여러가지가 있는데 대표적으로 UTF8 UTF16 등이 있다.
- UTF8
- 알파벳, 숫자 는 1 바이트 씩 작성한다.(ASCII와 동일한 번호)
- 유럽 지역의 문자는 2 바이트 씩 작성한다.
- 한글, 한자 등 3 바이트 씩 작성한다.
- UTF16
- 알파벳, 숫자, 한글, 한자 등 거의 대부분의 문자를 2 바이트로 작성한다.
- 매우 예외적인 고대 문자만 4바이트 를 차지하는데 이는 사실상 무시해도 된다.
wchar_t는 UTF16을 사용한다.
문자열
문자열은 문자들이 열을지어서 모여 있는 것이다. 즉 문자의 배열이다. 배열에 대해 자세히 배우지 않았으니 나중에 제대로 소개하겠다.
정수는 1~8 바이트로 고정 길이가 정해져 있는데 문자열은 그럴까?? 그러지 않는다. 그 부분이 나중에 설명하겠다.
단, 문장의 끝은 항상 NULL(\0)가 항상 들어가 있다는 점은 꼭 기억해야한다.
'C++ > 기초' 카테고리의 다른 글
[C++] 코드의 흐름 제어 - 1 (분기문, 반복문) (1) | 2023.11.23 |
---|---|
[C++] 데이터 가지고 놀기 - 2 (데이터 연산, const) (0) | 2023.11.23 |
[Assemble] SASM - 5 (1) | 2023.11.21 |
[Assemble] SASM - 4 (0) | 2023.11.21 |
[Assemble] SASM - 3 (1) | 2023.11.21 |