본문 바로가기

별걸다하는 IT/프로그래밍언어

[C/C++/Java 강좌] 비트 연산자2편- or연산자 (| 연산자) 개념 정리 및 활용, 실습 예제(bitset, toBinaryString)

[Java, C, C++ 프로그래밍 강좌 목차 편, 링크 모음]

안녕하세요

지난 포스팅에서 AND 연산자에 대해 다뤘었는데요.

오늘은 OR 연산자에 대해 알아보려고 합니다. 

비트 연산자의 종류

시작하기 전에 비트 연산자가 뭐뭐 있는지 표로 정리하고 갈게요

연산자

연산자의 기능

결합방향

&

비트 단위로 AND 연산을 한다. ex) num1 & num2

->

|

비트 단위로 OR 연산을 한다. ex) num1 | num2

->

^

비트 단위로 XOR 연산을 한다. ex) num1 & num2;

->

~

단한 연상자로서 피연산자의 모든 비트를 반전시킨다.

ex) ~num;

<-

<<

피연산자의 비트 열을 왼쪽으로 이동시킨다.

ex) num<<2; //num은 변화 없음, 두 칸 왼쪽 이동 결과 반환

->

>>

피연산자의 비트 열을 오른쪽으로 이동시킨다.

ex) num>>2; //num은 변화 없음, 두 칸 오른쪽으로 이동 결과만 반환

->

(참고로 <<,>>는 비트를 연산하기보다 이동시키기 때문에 비트 이동 연산자(쉬프트 연산자)에 좀 더 가깝지만 결국 다 비트를 다루기 때문에 한 데 묶었어요.)

시작하기 전, 다시 한 번 비트연산자 종류 확인하고 가기~~ 오늘 주인공은 논리연산자 or가 아닌 or 비트연산자입니다.

▼ AND연산자 포스팅이 궁금하신 분은 아래 링크를 참고해주세요.

https://jhnyang.tistory.com/162

 

[프로그래밍C++,Java 생기초] 비트 연산자1(bitwise operator)- & AND연산자 개념 정리 및 활용, 실습 예제(

[Java, C, C++ 프로그래밍 강좌 목차 편, 링크 모음] 오늘 프로그래밍 기초 편에서는 연산자 중 비트 연산자에 대해 다뤄볼게요 처음에 프로그래밍을 배울 때 대입연산자나 산술연산자 같은 경우는

jhnyang.tistory.com

| - or 연산자

저 작대기가 영문자 L이 아니고 'shift + \'에 해당하는 문자입니다. 

or 비트연산자는 두 비트 중 하나라도 true면 다른 값이 false든 true든 상관없이 true를 반환해요. (0은 false, 1은 true)

조건식에서 주로 사용되는 or 논리연산자 '||'와 헷갈리지 않도록 합시다. or논리연산자는 작대기가 두개지만 or비트연산자는 작대기가 하나예요

저번 포스팅에서 배웠던 AND연산자도 같이 낑겨서 표를 만들어봤어요.

AND연산자는 두 개 다 true여야만 true를 리턴했는데 OR연산자는 맨 첫 행 flase, false를 제외하고는 전부다 1(true)를 리턴하고 있어요. 둘 중 하나라도 1이 있음 결과도 1~!

--c언어
#include <stdio.h>
int main()
{
   int a = 10, b = 4;
   printf("a | b = %d ", a | b);
   return 0;
}

간단하게 결과를 확인할 수 있는 코드를 작성해보았습니다.

값 10과 4를 OR연산했는데 결과가 14로 나왔군요.ㅎㅎ

왜 이런 결과가 나왔는지는 이렇게 이진수로 풀어서 생각해보면 쉽게 확인하실 수 있습니다. 

 

[C++_2진수 출력으로 확인하면서 OR연산하기 -bitset]

#include <bitset>
#include <iostream>
using namespace std;
int main() 
{
	int num1=0, num2=0, result=0;
	cout<<"OR연산할 두 수를 입력하시오:\n";
	cin >> num1 >> num2;
	result = (num1 | num2);
	cout << "10진수 num1:\t" << num1 << "\t2진수 num1:\t" << bitset<8>(num1) << endl;
	cout << "10진수 num2:\t" << num2 << "\t2진수 num2:\t" << bitset<8>(num2) << endl;
	cout << "10진수 result:\t" << result << "\t2진수 result:\t" << bitset<8>(result);
}

저번처럼 bitset을 사용해서 해당 변수가 갖고 있는 값의 이진수 형태를 출력해보았습니다.

이진수를 출력함으로써 10과 3을 or연산했을 때 11이 나오는 원리에 대해 한 번에 확인할 수 있어요 ㅎㅎ

 

[JAVA_2진수 출력으로 확인하면서 OR연산하기 - toBinaryString]

자바로도 이진수 표현하는 방법은 지난 비트연산자 포스팅에서 자세히 다뤘었어요.

public class Main {
	 public static void main(String[] args) {
		 int num1 = 15, num2 =20;
		 String bit1 = String.format("%8s", Integer.toBinaryString(num1)).replace(' ', '0');
		 String bit2 = String.format("%8s", Integer.toBinaryString(num2)).replace(' ', '0');
		 System.out.println(bit1);
		 System.out.println(bit2);
		 System.out.println(String.format("%8s", Integer.toBinaryString(num1 | num2)));
	 }
}

저번과 동일하게 요렇게 출력해서 확인해줍시다.

비트 연산자 쓰임새, 활용

업무에서 비트연산자가 많이 쓰이지만, 학생들이 개발하면서 접하기는 쉽지 않죠.

비트 연산자는, 필드 플래그라던가, 데이터 결함 체크하는 패리티비트나 네트워크에서 flow control 알고리즘이라던가,, 

압축이나 암복호화 등 여러 곳에서 유용하게 쓰이고 있어요.

 

저번 AND 비트연산자 포스팅에서 '스위치 ONOFF 상태 확인하기' 예시를 들었던 것처럼 비슷한 예시로 상황을 재현해봅시다.

#include <iostream>
#include <bitset>
using namespace std;
int main()
{
	char flag = 5;
	cout << bitset<4>(flag) << endl; //0101로 두 번째 스위치와 마지막 스위치가 켜져있네요
	if (flag & 1) {
		cout << "마지막 스위치가 켜져 있다" << endl;
	}
	if (flag & 2) {
		cout << "세 번째 스위치가 켜져 있다" << endl;
	}
	if (flag & 4) {
		cout << "두 번째 스위치가 켜져 있다" << endl;
	}
	if (flag & 8) {
		cout << "첫 번째 스위치가 켜져 있다" << endl;
	}
	return 0;
}

저번시간에 이렇게 AND 비트연산자 예시를 들었었는데요. 저건 이미 flag가 5로 0101 상태로 켜져있는 상태잖아요. 원래 0000이였을 때, 원하는 스위치를 키는 행위를 OR연산자로 만들어봅시다.

#include <iostream>
#include <bitset>
using namespace std;
int main()
{
	//초기 스위치 (다 꺼진 상태)
	char flag = 0x00;
	cout << "초기스위치:\t"<< bitset<4>(flag) << endl;

	//스위치 ON!
	flag |= 0x01;   //'flag = flag | 0x01' 과 동일   
	flag |= 0x04;
	cout << "스위치ON 이후:\t" << bitset<4>(flag) << endl;

	//스위치 판별 
	if (flag & 1) {
		cout << "마지막 스위치가 켜져 있다" << endl;
	}
	if (flag & 2) {
		cout << "세 번째 스위치가 켜져 있다" << endl;
	}
	if (flag & 4) {
		cout << "두 번째 스위치가 켜져 있다" << endl;
	}
	if (flag & 8) {
		cout << "첫 번째 스위치가 켜져 있다" << endl;
	}
	return 0;
}

OR는 내가 가지고 있는 BIT위치의 값이 1이면 결과도 무조건 1을 리턴해주는 특성을 가지고 있기 때문에 이렇게 사용할 수 있습니다.

 

자, 똑같은 사용법인데 다른 상황극을 들어봅시다.

웹페이지를 만드는데, 유저마다 권한이 달라서 접근제한을 설정하려고 합니다.

관리자, 매니저, 개발자, 판매자, 구매자 등 유저레벨이 있다고 가정할게요.

#define ACCESSON(x, y) (x)|=(y)
#define HASACCESS(x, y) x & y ? 1:0
#include <stdio.h>
#define ROOT		0x01
#define MANAGER		0x02
#define DEVELOPER	0x04
#define SELLER		0x08
#define BUYER		0x10
int main()
{
	unsigned char access_type = 0x00;

	ACCESSON(access_type, ROOT);
	ACCESSON(access_type, MANAGER);
	ACCESSON(access_type, SELLER);

	if (HASACCESS(access_type, SELLER))
	{
		printf("구매자는 권한이 있다\n");
	}
	if (HASACCESS(access_type, BUYER))
	{
		printf("판매자는 권한이 있다\n"); //안나오겠죠?
	}
	return 0;
}

ACCESSON하면 해당 페이지에 접근 권한을 설정해주는 겁니다.

예제코드에서는 관리자, 매니저, 판매자가 이 페이지에 접근가능하도록 설정해줬습니다.

HASACCESS는 특정 레벨의 유저가 해당 페이지에 접근 가능한지 체크하는 매크로입니다.

판매자는 권한 설정을 해주지 않았으니 출력되지 않고, 구매자 부분은 출력되겠죠?ㅎㅎ

 

0x10은 뒤에서 다섯번째 자리가 on된 00010000을 의미하는데 헥사로 보니까 좀 보기 불편하죠 

C++14버전부터는 바이너리 리터럴을 지원하고 있습니다.

#define ACCESSON(x, y) (x)|=(y)
#define HASACCESS(x, y) x & y ? 1:0
#define ROOT		0b0000'0001
#define MANAGER		0b0000'0010
#define DEVELOPER	0b0000'0100
#define SELLER		0b0000'1000
#define BUYER		0b0001'0000

0b로 시작하면 바이너리(binary)라는 뜻이예요.  0x00을 바이너리로 표현하신다면 0b00000000로 표현해도 되지만 자리수가 너무 길어서 알아보기 힘들 때는 4자리 단위로 (')를 써서 위처럼 보기 쉽게 구분해줘도 됩니다.

 

권한을 부여했으면 권한을 해제할 수도 있어야겠죠?ㅎㅎ 다음 시간에는 not연산자와 XOR연산자에 대해서 같이 살펴봅시다. 오늘은 여기까지입니다. 도움이 되셨다면 좋아요 :) 고생하셨어요.