데이터 연산(산술 연산)
데이터를 가공하는 것이나 다름없다.
산술 연산자는 대입 연산과 사칙 연산 등이 있다.
대입 연산
int a = 0;
int b = 1;
a = b;
a라는 이름의 바구니를 할당하고 안에 0을 넣는다. b라는 이름의 바구니를 할당하고 안에 1을 넣는다.
a=b;는 a를 b에 대입하고 b를 반환하라는 의미이다. 이 말의 의미는 b 라는 바구니 안에 있는 값을, a 라는 바구니 안에다가 복사한다는 의미가 된다.
즉, 저 코드를 전부 실행하면 둘 다 1이라는 값을 가지게 된다.
프로그래밍을 하면서 가장 많이 사용하는 산술 연산자 이다.
그렇다면 사칙 연산은 언제 사용할까??
데미지를 계산한다던지, 체력이 닳는다던지 등등 우리가 생각하는 모든걸 사칙 연산을 통해 계산한다.
a = b + 3; // 덧셈 add
a = b - 3; // 뺄셈 sub
a = b * 3; // 곱셈 mul
a = b / 3; // 나눗셈 div
a = b % 3; // 나머지 div
//자기자신
a += 3; // a = a + 3;
a -= 3;
a *= 3;
a /= 3;
a %= 3;
//증감 연산자
a = a + 1; // add eax, 1 -> inc eax
a++;
++a;
a--;
--a;
b = a++; // b = a 후 a 1증가
b = ++a; // b = b + (a + 1)
어셈블리 랑 크게 다르지 않으니 자세한 설명하지 않겠다.
위의 코드를 어셈블리로 확인하면 다음과 같다.
데이터 연산(비교 연산, 논리 연산)
우리가 사칙연산 등 위의 산술 연산을 통해 데이터의 틀을 만든 것이다. 그런데 비교연산은 언제 필요한가??
- ex) 체력이 0이 되면 사망
- ex) 체력이 30% 이하이면 궁극기 발동 (100 * hp / maxHp)
- ex) 경험치가 100 이상이면 레벨업
등등 많은 경우에 사용할 수 있다.
크게 4가지의 비교 연산이 있다.
#include <iostream>
using namespace std;
int a = 1;
int b = 2;
int main()
{
#pragma region 비교연산
// 언제 필요한가??
// ex) 체력이 0이 되면 사망
// ex) 체력이 30% 이하이면 궁극기 발동 (100 * hp / maxHp)
// ex) 경험치가 100 이상이면 레벨업
// a == b : a와 b의 값이 같은가?
// 같으면 1, 다르면 0
bool isSame = (a == b);
//a != b : a와 b의 값이 다른가?
// 다르면 1, 같으면 0
bool isDifferent = (a != b);
// a > b : a가 b보다 큰가?
// a >= b : a가 b보다 크거나 같은가?
bool isGreater = (a > b);
// a < b : a가 b보다 작은가?
// a <= b : a가 b보다 작거나 같은가?
bool isSamller = (a < b);
#pragma endregion
}
그렇다면 이것만 가지고 모든걸 해결 할 수 있나. 그건 또 아니다. 조건에 대한 논리적 사고가 필요할 때가 생긴다.
여러 정보를 모아 하나의 정보로 판단해야할 때가 있다.
- ex) 로그인 할 때 아이디도 같고 AND 비밀번호도 같아야 한다.
- ex) 길드 마스터이거나 or 운영자 계정이면 길드 해산이 가능하다.
등등 사용이 가능하다.
#include <iostream>
using namespace std;
int a = 1;
int b = 2;
bool isSame;
bool isDifferent;
bool isGreater;
bool isSamller;
int main()
{
#pragma region 비교연산
// 언제 필요한가??
// ex) 체력이 0이 되면 사망
// ex) 체력이 30% 이하이면 궁극기 발동 (100 * hp / maxHp)
// ex) 경험치가 100 이상이면 레벨업
// a == b : a와 b의 값이 같은가?
// 같으면 1, 다르면 0
isSame = (a == b);
//a != b : a와 b의 값이 다른가?
// 다르면 1, 같으면 0
isDifferent = (a != b);
// a > b : a가 b보다 큰가?
// a >= b : a가 b보다 크거나 같은가?
isGreater = (a > b);
// a < b : a가 b보다 작은가?
// a <= b : a가 b보다 작거나 같은가?
isSamller = (a < b);
#pragma endregion
#pragma region 논리연산
// ! not
// 0 이면 1, 그 외 0
bool test = !isSame;
// && and
// a %% b -> 둘다 1이면 1, 그 외 0
test = (a <= 0 && isDifferent);
// || or
// a || b -> 둘 중 하나라도 1 이면 1(둘다 0이면 0)
test = (a > 0 || isDifferent);
#pragma endregion
}
데이터 연산(비트 연산, 비트 플래그)
비트 연산은 프로그래밍에서 많이 사용되지 않지만, 그래도 알고는 있어야한다. 그러면 언제 필요한가?
비트 단위의 조작이 필요할 때 주로 사용한다. 대표적으로 BitFlag에 사용한다.
#include <iostream>
using namespace std;
int a = 1;
int b = 2;
bool isSame;
bool isDifferent;
bool isGreater;
bool isSamller;
int main()
{
#pragma region 비트 연산
// ~ bitwise not
// 단일 숫자의 모든 비트를 대상으로, 0은 1, 1은 0으로 뒤바꿈
// & bitwise and
// 두 숫자의 모든 비트 쌍을 대상으로 and를 한다.
// | bitwise or
// 두 숫자의 모든 비트 쌍을 대상으로 or를 한다.
// ^ bitwise xor
// 두 숫자의 모든 비트 쌍으로 대상으로, xor를 한다.
// << 비트 좌측 이동
// 비트열을 N만큼 왼쪽으로 이동
// 왼쪽의 넘치는 N개의 비트는 버린다. 새로 생성되는 N개의 비트는 항상 0이다.
// *2를 할 때 자주 보이는 패턴 == 비트에 *2를 할때랑 << 1 이랑 같다.
// >> 비트 우측 이동
// 비트열을 N만큼 오른쪽으로 이동
// 오른쪽의 넘치는 N개의 비트는 버림.
// 왼쪽 생성되는 N개의 비트는
// - 부호 비트가 존재할 경우 부호 비트를 따라감.(부호 있는 정수라면 이 부분을 유의)
// - 아니면 0
// 0b0000 [무적][변이][스턴][공중에뜸]
// 만약 이런 상태이상들을 bool을 만들어서 관리할 경우
// 가능은 하다. 하지만 만약 상태이상이 수백개 있는 경우라면, 아이템이 수천개 있는 경우라면
// bool은 1바이트이고 우리가 사용하는건 1비트 이기 때문에 7비트를 상태이상 갯수당 손해를 본다.
// 하지만 0010 의 비트를 현재 스턴 상태 등으로 기록하면 메모리를 아낄 수 있다.
// 결국 정수랑 똑같다.
unsigned char flag;
// 무적 상태로 만든다.
flag = (1 << 3);
// 변이 상태를 추가한다. (무적 + 변이)
flag |= (1 << 2);
// 무적인지 확인하고 싶다(다른 상태는 신경쓰지 않는다.)
// bitmask
bool invincible = ((flag & (1 << 3)) != 0);
// 무적 이거나 스턴 상태 인지 확인하고 싶다면?
bool invincibleOrstun = ((flag & ((1 << 3) | (1 << 1))));
#pragma endregion
}
Const
위의 bitmask를 만들 때 숫자를 그냥 집어넣는 하드 코딩을 했다. 그렇다고 하면 만약 상태이상의 순서가 바뀌게 된다면 모든 코드를 찾아서 전부 수정해야할 것이다. 그렇기 때문에, const 키워드를 사용해 한번 정해지면 절대 바뀌지 않는 값들을 정해준다. 즉 변수를 상수화 시켜야 한다.
#include <iostream>
using namespace std;
const int AIR = 0;
const int STUN = 1;
const int INVINCIBLE = 2;
const int POLY = 3;
int main()
{
#pragma region 비트 연산
unsigned char flag;
// 무적 상태로 만든다.
flag = (1 << INVINCIBLE);
// 변이 상태를 추가한다. (무적 + 변이)
flag |= (1 << POLY);
#pragma endregion
}
const를 붙였으면 초기값을 반드시 지정해줘야한다.
'C++ > 기초' 카테고리의 다른 글
[C++] 코드의 흐름 제어 - 2 (가위-바위-보, 열거형) (1) | 2023.11.23 |
---|---|
[C++] 코드의 흐름 제어 - 1 (분기문, 반복문) (1) | 2023.11.23 |
[C++] 데이터 가지고 놀기 - 1 (정수, 불리언, 부동소수점, 문자열) (1) | 2023.11.22 |
[Assemble] SASM - 5 (1) | 2023.11.21 |
[Assemble] SASM - 4 (0) | 2023.11.21 |