언리얼 - C++ 7 : define, 비트 연산자

김정환·2025년 3월 16일

Unreal C++

목록 보기
7/37

1️⃣ 비트 연산자

  • 자주 사용하나 상대적으로 사용 빈도가 낮음
  • 학습 때는 이해하나, 시간이 지나면 잊으니 자주 상기시켜야 함.
  • 비트 단위로 실행하는 연산자

비트 시프트 <<, >>

  • 비트를 화살표 방향으로 한 칸씩 밀어냄.
  • 1 byte
unsigned char byte = 1;
=> 0000 0001

byte << 1; // 왼쪽으로 한 칸
=> 0000 0010
  • 십진수에서 자릿수 한 칸 이동은 10배 증가를 의미
    • 이진수에서 한 칸 이동은 2배 증가
    • 비트가 한 자리 올라간다 == 2배 증가
0000 1010 : 10

<< 1 // 1 비트 이동

0001 0100 : 20

  • byte <<= 1; : 왼쪽으로 이동하고 대입한다.
    byte = byte << 1;이 코드와 동일
  • byte <<= 2; : 2칸 왼쪽으로 이동 4배
  • byte <<= 3; : 3칸 왼쪽으로 이동 8배
byte >>= 1; // 1칸 오른쪽으로 이동 1/2
  • 나머지가 발생하지 않나?
    • 별도의 나머지 처리 구문이 없음.
      비트 자료형에서 나머지는 제거됨.
    • 즉, 2로 나눈 몫에 해당.
  • byte >>= n; : 2n을 나눈 몫

비트 곱, 합, xor, 반전

비트 곱 : &

각 비트의 자리에 대해서 두 값이 모두 1이면 1

1011 0111
1110 1111

1010 0111

비트 합 : |

각 비트의 자리에 대해서 두 값 중 하나만 1이어도 1

1011 0111
1110 1111

1111 1111

반전 : ~

각 자리의 비트를 뒤집음

1011 0111
~ // 반전

0100 1000

xor : ^

두 각 자리의 비트가 같으면 0, 다르면 1
1. 두 비트가 같으면 1, 다르면 0으로 계산
2. 반전(~)시키기

1011 0111
1110 1111

0101 1000

비트 연산자의 사용처

  • 의외로 정말 많이 사용함.
    • 게임에서도 사용이 잦음
  • 그 전에 전처리 관련 설명 진행

➕ 전처리 구문

#(전처리 구문)
  • #으로 시작하는 구문
  • 모든 코드 중에서 전처리 구문을 먼저 처리.

define

  • 내가 원하는 어떤 값으로 치환해줌.
  • c#에서 쓰던 상수같이 어떤 값을 내가 원하는 값으로 선언해서 사용
#define SOME_STATE 1

int iStatus = SOME_STATE; // 1이 들어감.
// define 전처리 구문에서 처리해둔 것.

왜 쓰는가?

  • 장점 1 : 상태(화상, 독, 배고픔 등등)라는 어떤 변수를 만들고 싶을 때,
    각 상태가 중첩되어 사용될 수 있음.
    • 근데 이때, 화상 = 27, 배고픔 = 1 등등을 암기하고 있어야하나?
      • 변경 등에 취약해짐.
    • define을 사용함으로써 가독성 확보 가능.
#define BURN = 27
#define HUNGRY = 3

int iStatus = BURN;
iStatus = HUNGRY;
  • 장점 2 : 값의 변경이 필요할 때, 매크로 부분(define 구문)에서 값만 수정해주면 됨.
    유지보수성 향상
#define MAX_SIZE = 20; 
// => 요구에 따라 40으로 변경

int capacity[MAX_SIZE];

2️⃣ 비트 연산의 주 사용처

캐릭터 상태 구현 예시

#define HUNGRY 1

int iStatus = HUNGRY; 
  • 위처럼 상황이 있다고 할때, 상태는 int이므로 4 byte == 32 bit.
    • 즉, 비트 단위로 상태를 32칸에 해당하는 값으로 표현할 수 있음.
  • 상태를 표현하기 위해선 겹치지 않는 자리가 필요.
0000 0000 0000 0000 0000 0000 0000 0000
  • 이와 같이 총 32칸이 있고 HUNGRY를 1로 설정함
0000 0000 0000 0000 0000 0000 0000 0001 : 배고픈 상태
  • 각 자리마다 하나의 상태를 표현할 수 있으므로 총 32개의 상태를 중첩가능하게 표현 가능
    • 유니티 Layer와 같은 방식
#define HUNGRY	1 // 배고픔 : 첫번째 칸 1
#define THIRSTY 2 // 갈증 : 두번째 칸 2
#define TIRED	4 // 피로 : 세번째 칸이어야 하므로 4가 들어감
#define ~~~		8 // 다음칸~
0000 0000 0000 0000 0000 0000 0000 0001 : 배고픔
0000 0000 0000 0000 0000 0000 0000 0010 : 갈증
0000 0000 0000 0000 0000 0000 0000 0100 : 피로
~~

비트 연산자 활용

상태 부여 |

#define HUNGRY	1 // 배고픔 : 첫번째 칸 1
#define THIRSTY 2 // 갈증 : 두번째 칸 2
#define TIRED	4 // 피로 : 세번째 칸이어야 하므로 4가 들어감

unsigned int iStatus = 0;
0000 0000 0000 0000 0000 0000 0000 0000

// 배고픔 상태 부여
iStatus |= HUNGRY; // 비트 합 연산 대입
0000 0000 0000 0000 0000 0000 0000 0000 : iStatus
0000 0000 0000 0000 0000 0000 0000 0001 : HUNGRY
0000 0000 0000 0000 0000 0000 0000 0001 : 합 연산 결과

// 갈증 상태 부여
iStatus |= THIRSTY; // 비트 합 연산 대입
0000 0000 0000 0000 0000 0000 0000 0001 : iStatus
0000 0000 0000 0000 0000 0000 0000 0010 : THIRSTY
0000 0000 0000 0000 0000 0000 0000 0011 : 합 연산 결과
  • iStatus는 배고픔과 갈증 상태가 부여된 값임.

상태 체크 &

if(iStatus & THIRSTY) // 비트 곱 연산
{
}

// 앞의 연산 직후 검사할 때
0000 0000 0000 0000 0000 0000 0000 0011 : iStatus
0000 0000 0000 0000 0000 0000 0000 0010 : THIRSTY

0000 0000 0000 0000 0000 0000 0000 0010 : 곱 연산 결과
=> 숫자로 표현하면 2
=> true: 0 이외의 모든 값.
=> 조건문은 true 반환

// 다른 경우
iStatus = HUNGRY;

iStatus & THIRSTY // 비트 곱연산 시,

0000 0000 0000 0000 0000 0000 0000 0001 : iStatus
0000 0000 0000 0000 0000 0000 0000 0010 : THIRSTY

0000 0000 0000 0000 0000 0000 0000 0000 : 곱 연산 결과
=> 숫자로 표현하면 0
=> false

상태 제거 1. xor

1101 상태
1001 상태로 만들고 싶음. == 0100 상태를 제거하고 싶음.

	1101
xor 0100 (같으면 0, 다르면 1)
	1001
  • 단, 이때는 문제가 있을 수 있음.
  • 원치 않는 상태인데 xor 연산으로 값이 변경될 수 있음.
    • 그러므로 먼저 상태를 if문으로 검사하고 연산하는 것이 좋음.
  • 그리고 특정 자리 비트를 제거할 땐 xor를 잘 쓰지 않음.ㄴ

상태 제거 2. ~, &

iStatus = THIRSTY;
iStatus &= ~THIRSTY;

0000 0000 0000 0000 0000 0000 0000 0010 : iStatus
1111 1111 1111 1111 1111 1111 1111 1101 : ~THIRSTY
0000 0000 0000 0000 0000 0000 0000 0000 : 비트 곱 결과

iStatus = HUNGRY;
iStatus |= THIRSTY;

0000 0000 0000 0000 0000 0000 0000 0001
0000 0000 0000 0000 0000 0000 0000 0010
0000 0000 0000 0000 0000 0000 0000 0011

iStatus &= ~THIRSTY;
0000 0000 0000 0000 0000 0000 0000 0011 : iStatus
1111 1111 1111 1111 1111 1111 1111 1101 : ~THIRSTY
0000 0000 0000 0000 0000 0000 0000 0001 : 비트 곱 연산 => HUNGRY만 남음.

이 형태는 암기하는 것이 좋음

iStatus &= ~THIRSTY; 
  • 특정 비트를 빼는 형태

비트 대응시키기

  • 32개를 계속 넣어주어야 하나?
#define HUNGRY	1
#define THIRSTY	2
#define TIRED	4
#define FIRE	8
#define COLD	16
...
  • 보통은 16진수를 활용
    • 0x 16진수 숫자란 의미
    • 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f
  • 이런 식으로 16진수를 활용하여 비트에 해당하는 순서로 값을 할당해서 사용.
#define HUNGRY	0x1 // 1
#define THIRSTY	0x2 // 2
#define TIRED	0x4 // 4
#define FIRE	0x8 // 8

#define COLD	0x10 // 16 16진법이므로 16이 되면 다음 자리로 이동
#define POISON	0x20 // 32
#define POISON	0x40 // 64
#define POISON	0x80 // 128

#define POISON	0x100 // 256
#define POISON	0x200 // 512
#define POISON	0x400 // 1024
#define POISON	0x800 // 2048
...

다른 예시

  • 윈도우 세팅에서도 창에 대한 설정을 이렇게 비트로 제공함.
profile
만성피로 개발자

0개의 댓글