CPP 여러가지 연산자, 비트플래그
산술 연산
대입과 사칙연산
int a = 10; // 대입: a에 10을 저장하고 10 반환
int b = a; // b에 a값 복사
// 사칙연산
int sum = a + b; // 덧셈
int diff = a - b; // 뺄셈
int product = a * b; // 곱셈
int quotient = a / b; // 나눗셈(몫)
int remainder = a % b; // 나머지
// 복합 대입
a += 3; // a = a + 3;
a *= 2; // a = a * 2;
증감 연산자
int a = 5;
int b = a++; // b = 5, a = 6 (후위: 대입 후 증가)
int c = ++a; // c = 7, a = 7 (전위: 증가 후 대입)
int d = a--; // d = 7, a = 6 (후위: 대입 후 감소)
int e = --a; // e = 5, a = 5 (전위: 감소 후 대입)
연산자 우선순위: *
, /
, %
→ +
, -
→ =
비교 연산
int hp = 30, maxHP = 100;
bool isDead = (hp == 0); // 같은가?
bool isAlive = (hp != 0); // 다른가?
bool isLowHP = (hp < maxHP * 0.3); // 30% 미만인가?
bool isFullHP = (hp >= maxHP); // 만피 이상인가?
모든 비교 연산은 1(true) 또는 0(false) 반환.
논리 연산
기본 연산자
bool isInvincible = true;
bool isDead = false;
// NOT (!)
bool canTakeDamage = !isInvincible; // false
// AND (&&) - 둘 다 true여야 true
bool shouldDie = (hp <= 0 && !isInvincible);
// OR (||) - 하나라도 true면 true
bool isAlive = (hp > 0 || isInvincible);
단축 평가 (Short-Circuit Evaluation)
C++ 문법으론 같은 결과일지라도 어셈블리에서 근소한 차이를 보이기에 성능 최적화를 위해 빠른 조건을 앞쪽에 작성하는게 좋음.
AND (&&): 왼쪽이 false면 오른쪽 실행 안 함
bool result = (hp <= 0 && checkInvincibility());
// hp > 0이면 checkInvincibility() 호출 안 됨
OR (||): 왼쪽이 true면 오른쪽 실행 안 함
bool result = (isGod || hasCheatCode());
// isGod가 true면 hasCheatCode() 호출 안 됨
성능 최적화:
// 좋은 예: 빠른 조건을 앞에
if (cheapCheck() && expensiveCheck()) { }
// 나쁜 예: 느린 조건을 앞에
if (expensiveCheck() && cheapCheck()) { }
비트 연산
기본 연산자
unsigned char a = 0b1100; // 12
unsigned char b = 0b1010; // 10
cout << (a & b); // 0b1000 = 8 (AND)
cout << (a | b); // 0b1110 = 14 (OR)
cout << (a ^ b); // 0b0110 = 6 (XOR)
cout << (~a); // 0b0011 = 3 (NOT, 4비트 기준)
비트 시프트
unsigned int x = 5; // 0b101
cout << (x << 1); // 0b1010 = 10 (*2 효과)
cout << (x << 2); // 0b10100 = 20 (*4 효과)
cout << (x >> 1); // 0b10 = 2 (/2 효과)
컴파일러 최적화: x * 2
→ x << 1
로 자동 변환됨
비트플래그 (BitFlag)
상태이상에서의 활용
// 0b0000 [무적][기절][변이][속박]
// bit: 3 2 1 0
enum StatusEffect {
BIND = 1 << 0, // 0b0001
POLYMORPH = 1 << 1, // 0b0010
STUN = 1 << 2, // 0b0100
INVINCIBLE = 1 << 3 // 0b1000
};
unsigned int flag = 0;
상태 추가/제거
// 무적 상태 추가
flag |= INVINCIBLE; // 0b1000
// 기절 상태 추가
flag |= STUN; // 0b1100
// 무적 상태 제거
flag &= ~INVINCIBLE; // 0b0100
// 모든 상태 제거
flag = 0;
상태 확인
// 무적 상태인가?
bool isInvincible = (flag & INVINCIBLE) != 0;
// 무적이거나 변이 상태인가?
bool isImmuneToAttack = (flag & (INVINCIBLE | POLYMORPH)) != 0;
// 특정 상태 조합인가?
bool isStunnedAndBound = (flag & (STUN | BIND)) == (STUN | BIND);
실무 활용 예제
// 권한 시스템
enum Permission {
READ = 1 << 0, // 0b001
WRITE = 1 << 1, // 0b010
EXECUTE = 1 << 2 // 0b100
};
unsigned int userPermission = READ | WRITE; // 0b011
// 실행 권한 확인
if (userPermission & EXECUTE) {
cout << "실행 가능";
} else {
cout << "권한 없음";
}
디스어셈블리로 확인 가능한 최적화
논리 연산 최적화
// C++ 코드
bool result = (hp <= 0 && !isInvincible);
// 어셈블리 (슈도코드)
cmp hp, 0
jg skip_second_check // hp > 0이면 두 번째 조건 스킵
cmp isInvincible, 0
je set_true
skip_second_check:
mov result, 0
비트 시프트 최적화
int x = 10;
int doubled = x * 2; // 컴파일러가 x << 1로 변환
int quadrupled = x * 4; // 컴파일러가 x << 2로 변환
실제 사용시
비트플래그 사용 시 주의사항:
// 좋은 예: unsigned 타입 사용
unsigned int flag = 0;
// 나쁜 예: signed 타입 (부호 비트 문제)
int flag = 0; // 최상위 비트가 부호 비트가 됨
가독성을 위한 매크로:
#define HAS_FLAG(flags, flag) ((flags & flag) != 0)
#define ADD_FLAG(flags, flag) (flags |= flag)
#define REMOVE_FLAG(flags, flag) (flags &= ~flag)
if (HAS_FLAG(playerStatus, INVINCIBLE)) {
cout << "무적 상태";
}