본문 바로가기

강의자료/C/C++

029. 비트 연산에 대해서 이해하자.

◈ 이 글은 강의를 위하여 제가 직접 작성한 내용입니다. 따라서 퍼가실 경우, 출처를 명확히 해주시기 바랍니다!!
◈ This ariticle was written by me for teaching. So if you want to copy this article, please clarify the source!!


2,8,16진수에 대해서 먼저 이해하고 비트 연산자를 알아보도록 하자.
// 2,8,16진수에 대해 설명한다.
/*
1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21
1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26 27 30 31

8421   8421 
1011 / 0101 = b5 = b*16 + 5 = 11*16 + 5 = 176 + 5 = 181
1+2+8 = b, 1+4 = 5

21   421   421
10 / 110 / 101 = 265 = 2 * 64 + 6 * 8 + 5 = 128 + 48 + 5 = 181
2, 2+4=6, 1+4 = 5
*/

// 기본적인 연산자에 대한 설명을 한다.
/*
AND(&)
1&1=1
1&0=0
0&1=0
0&0=0

OR(|)
1&1=1
1&0=1
0&1=1
0&0=0

XOR(^)
1&1=0
1&0=1
0&1=1
0&0=0

1의보수(~)
~1=0
~0=1
~1001=0110

컴퓨터에서는 음수를 2의 보수로 표현한다.
2의 보수는 1의 보수에 1을 더하면 된다.
즉, ~5의 의미는 5의 1의 보수이므로 2의 보수인 -5에서 1을 빼주면 -6이 된다.
int a = 5;
~a = -6이 된다.

 00000000 00000000 00000000 00001010 = 10
 11111111 11111111 11111111 11111010 = -6
끝자리 1은 버림                  421
100000000 00000000 00000000 00000100 = 4
*/

#include  
using namespace std;
//shift 연산
int main( )
{

	cout << "\n-------- Shift 연산 -------------" << endl;
	cout << 65 << " << " << 3  << " = " << (65 << 3) << endl;  //01000001 << 3
	cout << 65 << " >> " << 3  << " = " << (65>>3) << endl;  //01000001 >> 3
	cout << endl; 

	int n=65;
	for(int i=0;i <= 32/3;i++)
	{
		int num=(n&(7)); //7 -> 111(2진수) 
		//00 000 000 000 000 000 000 000 001 000 001 & 111
		cout << num;
		n = n>>3;	 //오른쪽 쉬프트 01100 >>3은 01
		//00 000 000 000 000 000 000 000 001 000 3칸(001) 버림 
	}//반대 방향으로 출력
	cout << " <--여기서 부터 읽자." << endl;
	return 0;
}

// 2진수 출력구문으로 변경해보자.
// 수정해야 할 곳은 3군데이다.
// 1. 32/3 -> 32
// 2. 7 -> 1
// 3. n>>3 -> n>>1

비트 연산을 이용하여 플래그를 조작해보자.
#include  
using namespace std;
typedef unsigned int	 UINT;

/*
1	->	00000001
2	->	00000010
4	->	00000100
8	->	00001000
16	->	00010000
*/

const UINT PLAYER_NONE		=	0;
const UINT PLAYER_ATTACK	=	1;
const UINT PLAYER_DEFENCE	=	2;
const UINT PLAYER_MAGIC		=	4;
const UINT PLAYER_HEAL		=	8;
const UINT PLAYER_BUFF		=	16;

void ShowPlayerStatus(UINT status);

void main( )
{
	UINT playerStatus = PLAYER_ATTACK | PLAYER_MAGIC | PLAYER_BUFF;
	ShowPlayerStatus(playerStatus);
}

void ShowPlayerStatus(UINT status)
{
	if(status & PLAYER_ATTACK) cout << "플레이어가 공격중입니다." << endl;
	if(status & PLAYER_DEFENCE) cout << "플레이어가 방어중입니다." << endl;
	if(status & PLAYER_MAGIC) cout << "플레이어가 마법중입니다." << endl;
	if(status & PLAYER_HEAL) cout << "플레이어가 치료중입니다." << endl;
	if(status & PLAYER_BUFF) cout << "플레이어가 버프중입니다." << endl;
}
연습문제
// 2진수를 정방향으로 출력하시오.
#include 
using namespace std;
void ShowToBinary(int NUM);
void main()
{
	int num = 0;
	cout << "양 또는 음의 10진 정수를 입력하세요. " << endl;
	cin>>num;
	cout << "12345678901234567890123456789012" << endl << endl;
	ShowToBinary(num);
}
void ShowToBinary(int NUM)
{
	const int BinarySizeOfInt = sizeof(NUM)*8;
	char BIN[BinarySizeOfInt+1];

	BIN[BinarySizeOfInt] = '\0';

	for(int X=0, Y=BinarySizeOfInt-1; X < BinarySizeOfInt; X++, Y--)
	{
		int LSB = NUM & (1 << X);
		if(LSB) BIN[Y] = '1';
		else BIN[Y] = '0';
	}

	cout << BIN << endl;
}

// 11부터 50까지의 숫자를 8로 나눈 몫과 나머지를 구하되 비트연산자만을 이용하시오.
// 출력결과는 아래와 같다.
/*
Index : 11	11/8 = 1	11%8 = 3
Index : 12	12/8 = 1	12%8 = 4
Index : 13	13/8 = 1	13%8 = 5
		.
		.
		.
Index : 47	47/8 = 5	47%8 = 7
Index : 48	48/8 = 6	48%8 = 0
Index : 49	49/8 = 6	49%8 = 1
Index : 50	50/8 = 6	50%8 = 2
*/

#include 
using namespace std;
void main()
{
	for( int index=11; index<=50; index++ )
	{
		int indexDiv8 = index >> 3;
		int indexMod8 = index & 7;
		cout << "Index : " << index << "\t" << index << "/8 = " << indexDiv8 << "\t" << index << "%8 = " << indexMod8 << endl;
	}
}

#include  
using namespace std;
typedef unsigned int	 UINT;

const UINT PLAYER_NONE		=	0;
const UINT PLAYER_ATTACK	=	1;
const UINT PLAYER_DEFENCE	=	1 << 1;
const UINT PLAYER_MAGIC		=	1 << 2;
const UINT PLAYER_HEAL		=	1 << 3;
const UINT PLAYER_BUFF		=	1 << 4;

void SetStatus(UINT& status, UINT flag);
void AddStatus(UINT& status, UINT flag);
void DelStatus(UINT& status, UINT flag);

void ShowPlayerStatus(UINT status);

void main( )
{
	UINT playerStatus = PLAYER_NONE;

	SetStatus(playerStatus, PLAYER_DEFENCE);
	ShowPlayerStatus(playerStatus);

	AddStatus(playerStatus, PLAYER_HEAL);
	ShowPlayerStatus(playerStatus);

	AddStatus(playerStatus, PLAYER_ATTACK | PLAYER_BUFF);
	ShowPlayerStatus(playerStatus);

	DelStatus(playerStatus, PLAYER_HEAL | PLAYER_DEFENCE);
	ShowPlayerStatus(playerStatus);

	SetStatus(playerStatus, PLAYER_MAGIC | PLAYER_BUFF);
	ShowPlayerStatus(playerStatus);
}

void SetStatus(UINT& status, UINT flag)
{
	status = flag;
}
void AddStatus(UINT& status, UINT flag)
{
	status |= flag;
}
void DelStatus(UINT& status, UINT flag)
{
	status &= ~flag;
	// XOR연산을 사용해도 제거할 수는 있지만,
	// 없는 값을 제거하려고 하면 오히려 추가가 되어버리므로 사용해선 안된다.
}
bool HasStatus(UINT& status, UINT flag)
{
	return ((status & flag) == flag);
}
void ShowPlayerStatus(UINT status)
{
	cout << "NowStatus is..." << endl;
	if(HasStatus(status, PLAYER_ATTACK))	cout << "   PLAYER_ATTACK" << endl;
	if(HasStatus(status, PLAYER_DEFENCE))	cout << "   PLAYER_DEFENCE" << endl;
	if(HasStatus(status, PLAYER_MAGIC))		cout << "   PLAYER_MAGIC" << endl;
	if(HasStatus(status, PLAYER_HEAL))		cout << "   PLAYER_HEAL" << endl;
	if(HasStatus(status, PLAYER_BUFF))		cout << "   PLAYER_BUFF" << endl;
	cout << endl;
}
// void ShowPlayerStatus(UINT status)
// {
// 	cout << "NowStatus is..." << endl;
// 	if(status & PLAYER_ATTACK)		cout << "   PLAYER_ATTACK" << endl;
// 	if(status & PLAYER_DEFENCE)		cout << "   PLAYER_DEFENCE" << endl;
// 	if(status & PLAYER_MAGIC)		cout << "   PLAYER_MAGIC" << endl;
// 	if(status & PLAYER_HEAL)		cout << "   PLAYER_HEAL" << endl;
// 	if(status & PLAYER_BUFF)		cout << "   PLAYER_BUFF" << endl;
// 	cout << endl;
// }