본문 바로가기
C++/기초

C++ 기초 : define / 비트 연산자 (1)

글: 시플마 2024. 2. 15.

비트 연산자를 이용하여 비트 단위로 연산할 수 있습니다.

비트 연산자 중 시프트 연산자라는 것이 있습니다.

<<, >>로 씁니다.

 

<<는 비트를 왼쪽으로 옮깁니다.

아래와 같은 코드를 입력했을 때 어떻게 작동하는지 

살펴보면서 설명하겠습니다.

unsigned char num = 1;
num << 1;	//비트를 왼쪽으로 한 칸 옮긴다.

 

 

위 코드에서 char형 변수 num의 비트를 보면 아래와 같을 것입니다.

0 0 0 0 0 0 0 1

 

 

그 다음 시프트 연산 <<를 통해 비트를 1칸 옮깁니다.

0 0 0 0 0 0 1 0

 

비트를 한 칸 옮기면서 1이었던 값이 2가 되었습니다.

 

 

이번에는 두 칸 옮겨 볼까요?

unsigned char num = 1;
num << 2;	//비트를 왼쪽으로 두 칸 옮긴다.

 

 

위 코드에서 char형 변수 num의 비트 상태는 아래와 같을 것입니다.

0 0 0 0 0 0 0 1

 

 

그 다음 시프트 연산 <<를 통해 비트를 두 칸 옮기게 됩니다.

0 0 0 0 0 1 0 0

 

 

처음 1이었던 값이

시프트 연산 <<를 통해 비트를 두 칸 옮기게 되었고

결과적으로 4가 되었습니다.

 

여기서 알 수 있는 사실은

비트를 왼쪽으로 한 칸 옮길 때마다 

값이 두 배가 된다는 것입니다.

 

십진수에서도 보면 02라는 값에서

2를 왼쪽으로 한 칸 옮기면 20이 되죠.

십진수에서 기존 2라는 값을 왼쪽으로 한 칸 옮기니

10배가 증가한 20이 되었습니다.

 

그렇다면 이진수는 어떨까요? 

왼쪽으로 한 칸 옮기면 값이 2배가 증가하겠죠.

 

 


 

 

이번에는 비트 연산자 중

시프트 연산 >>은 어떻게 작동하는지 살펴보겠습니다.

 

아래 코드를 통해 살펴보죠.

unsigned char num = 10;
num >> 1;	//비트를 오른쪽으로 한 칸 옮긴다.

 

 

값이 10인 char형 변수 num이 있습니다.

0 0 0 0 1 0 1 0

 

 

값 10을 시프트 연산 >>를 수행하였습니다.

아래와 같이 될 것입니다.

0 0 0 0 0 1 0 1

 

계산하면 5가 나옵니다.

 

 

 

예를 하나 더 들어보죠.

unsigned char num = 4;
num >> 2;	//비트를 오른쪽으로 두 칸 옮긴다.

 

 

값 4를 

0 0 0 0 0 1 0 0

 

 

>> 연산을 통해 비트를 오른쪽으로 두 칸 옮겼습니다.

0 0 0 0 0 0 0 1

 

계산하면 1이 나옵니다.

 

여기서 알 수 있는 점은

한 칸 옮길 때 값이 2배가 되는 << 연산과 달리,

>> 연산을 하면 한 칸 옮길 때마다 값이 1/2배가 됩니다.

 

바꿔 말해

>> 연산을 통해 비트를 오른쪽으로 한 칸 옮길 때마다

기존 값이 절반으로 줄어듭니다.

즉, 오른쪽으로 한 칸 옮길 때마다 기존 값을 2로 나누는 것이죠.

 

그럼 홀수를 >> 연산하면 나머지는 어떻게 될까요?

 

아래와 같이 3을 표현하는 비트가 있다고 합시다.

0 0 0 0 0 0 1 1

 

 

3을 >> 연산을 통해 오른쪽으로 한 칸 옮겨봅니다.

0 0 0 0 0 0 0 1

 

계산하니 1이 나왔습니다.

 

>> 연산을 하면서 몫 부분만 남고

나머지 부분은 사라지는 것을 알 수 있습니다.

 

 


 

 

 

추가적으로 시프트 연산 후 그 값을 

바로 대입할 수도 있습니다.

<< 연산을 한 후에 대입하고 싶다면 <<=를

>> 연산을 한 후에 대입하고 싶다면 >>=를 사용하면 됩니다.

 

 

기존 2의 값을 가진 변수 num을

<< 연산을 통해 왼쪽으로 한 칸 옮긴 후 대입하고

그 값을 확인해 보니 4가 대입된 것을 확인할 수 있습니다.

 

 

이번에는

기존 8의 값을 가진 변수 num을

>> 연산을 통해 왼쪽으로 두 칸 옮긴 후 대입하고

그 값을 확인해 보니 2가 대입된 것을 확인할 수 있습니다.

 

 

 


 

 

 

비트 연산자의 또 다른 종류로는

&(곱) 연산자, |(합) 연산자, ~(반전) 연산자, ^(xor) 연산자가 있습니다.

 

 

& 연산은 비트가 둘 다 1인 경우만 1이 됩니다.

0 0 0 1 0 0 1 0

 

&

0 0 0 0 0 0 1 0

 

=

0 0 0 0 0 0 1 0

 

 

 

| 연산은 비트가 둘 중 하나라도 1이면 1이 됩니다.

0 0 0 1 0 0 1 0

 

|

0 0 0 0 0 0 1 0

 

=

0 0 0 1 0 0 1 0

 

 

 

~ 연산은 모든 비트를 반전시킵니다.

~

0 0 0 1 0 0 1 0

 

=

1 1 1 0 1 1 0 1

 

 

 

^ 연산은 비트를 비교하여 같으면 0, 다르면 1이 됩니다.

0 0 0 1 0 0 1 0

 

^

0 0 0 0 0 0 1 0

 

=

0 0 0 1 0 0 0 0

 

 

 


 

 

비주얼 스튜디오에서 C++ 개발을 할 때

'전처리기'라는 과정이 있습니다.

이는 모든 컴파일 과정 중 가장 먼저 수행됩니다.

 

전처리기 지시문 중 하나인 #define 지시문을 살펴보겠습니다.

#define 지시문은 매크로를 정의합니다.

즉, 코드 작성자가 정한 구문을 특정 숫자로 치환해 주는 역할을 합니다.

 

 

아래 코드를 보면

코드 맨 위에 #define 지시문이 있는 것을 확인할 수 있습니다.

전처리기 지시문은 코드 가장 맨 위에 작성합니다.

 

작성자가 임의로 정한 HUNGRY라는 구문을 1로 보겠다는 의미입니다.

 

컴파일을 수행하면 컴파일러는 "#define HUNGRY 1"을 보고 

코드로 내려가 HUNGRY 구문을 1로 바꾸는 과정을 먼저 수행합니다.

 

실행 결과 변수 status에 들어간 수를 보면 1이 대입된 것을 확인할 수 있습니다.

 

 

#define 지시문은 왜 사용하는 걸까요?

첫 번째 장점은 가독성입니다.

 

게임을 예로 들겠습니다.

전투 중, 배고픔, 죽음, 비행, 달리는 중, 걷는 중 등등

게임에서 플레이어 상태는 다양하게 존재합니다.

 

지시문을 사용하지 않는다면 각각 상태에 대응하는 수를 

코드 작성자가 외워야 합니다.

전투 중은 0, 배고픔은 1, 죽음은 2... 

 

그러나 아래 코드처럼 #define을 통해 정의해 놓으면 

#define BATTLE 0
#define HUNGRY 1
#define DEAD 2

 

 

플레이어 상태를 표현할 때 구문을 대입하면

단순히 숫자를 쓰는 것보다 훨씬 알아보기 쉽습니다.

 

 

두 번째 장점은 유지보수를 하기에 있어 용이하다는 점입니다.

 

예를 들어 자판기 시스템을 구축한다고 봅시다.

 

이 자판기는 음료수의 개수가 최대 20개까지 들어가는 자판기입니다.

그래서 20이라는 숫자를 음료수의 최대 개수로 생각하고

코드를 작성하였습니다.

 

그런데 A 자판기가 업그레이드되어 음료수를 최대 40개까지 넣을 수 있게 되었습니다.

음료수의 최대 개수를 20으로 생각하고 코드 내에서 20으로 작성하였는데

40개로 수정하기 위해 20이라는 수를 일일이 수정해야 하는 번거로움이 생깁니다.

 

만약 처음부터 #define 지시문을 통해

아래와 같이 작성하고

이를 코드 내에서 활용했다면 어땠을까요?

#define MAX_QUANTITY 20

 

 

음료수의 최대 개수가 40개로 늘어나면

아래와 같이 20을 40으로, 숫자만 바꿔 주면 간단하게 해결됩니다.

#define MAX_QUANTITY 40

 

 

 

 

 

 

강의 출처 : https://www.youtube.com/watch?v=PFc4g8mxOiI&list=PL4SIC1d_ab-aOxWPucn31NHkQvNPHK1D1&pp=iAQB


 

'C++ > 기초' 카테고리의 다른 글

C++ 기초 : 변수 / 함수 (1)  (0) 2024.02.18
C++ 기초 : 비트 연산자 (2)  (0) 2024.02.16
C++ 기초 : switch 구문 / 삼항 연산자  (0) 2024.02.12
C++ 기초 : if / else 구문  (0) 2024.02.10
C++ 기초 : 비교 연산자  (0) 2024.02.10