C언어를 사용하다보면 다양한 연산자들이 존재한다.
?와 같은 조건문을 간편하게 줄여주는 단항 연산자도 있고
&&와 ||과 같은 이항 논리연산자들도 자주 사용하게 된다.
한편, &와 |과 같은 이항 비트연산자들도 기본적인 문법 공부를 하다보면 마주하게 되지만 실상 코딩을 하다보면 어디에 사용되는지 잘 모르고 있었다.
때마침 학교에서 실습을 진행하며 비트연산자를 활용한 다양한 재미있는 문제들이 있어 이를 정리하고 공유하려 한다.
우선, 비트연산자들을 어떠한 용도로 사용하는지 점검한 후에 실습 문제들을 해결해보자.
흔히 and로 논리연산자에서 사용하는 &와 유사하다고 생각하면 좋다.
비트로 표현할 때 사용하는 숫자가 0과 1이므로 모두 0인 경우와 모두 1인 경우는 그대로, 0과 1이 섞인 경우는 0을 출력해준다.
조금 깊이 생각을 해보면 특정 자리의 비트가 0인지 1인지를 판단하는데 핵심적인 역할을 한다는 사실을 알 수 있다.
다음 2진수로 표현된 예시를 살펴보자.
10진수 기준 20 : 2진수 8비트로 표현 시 00010100
우측에서 5번째와 3번째 숫자인 1을 실제로 표현하고 싶다면 단항연산자인 ?과 함께 다음 방식으로 표현이 가능하다.
1. 00010000과 &연산 후에 00010000(16)이 그대로 나온다면 1로 출력 아니면 0으로 출력한다.
2. 00000100과 &연산 후에 00000100(4)가 그대로 나온다면 1로 출력 아니면 0으로 출력한다.
즉, 2진수로 표현하고자 하는 숫자는 수정하지 않은 채로 비교대상인 숫자들을 절반으로 바꿔가면서 &를 취해주면 각각 비트의 숫자를 확인할 수 있다.
<<칸만큼 2의 거듭제곱배를 한다거나 >>칸만큼 2의 거듭제곱으로 나눈다는 기본 개념을 응용하여 크게 3가지 경우에 사용할 수 있다.
1. 주어진 숫자를 원하는 비트의 2진수로 표현할 때
다음 2진수로 표현된 예시를 살펴보자.
10진수 기준 20 : 2진수 8비트로 표현 시 00010100
&연산자와는 다르게 비교대상인 숫자는 수정하지 않은 채로 표현하고자 하는 숫자인 20의 비트를 왼쪽으로 한칸씩 움직이며 총 8번 <<해주면 된다.
위와 같은 논리로 10000000(128)과 비교하여 128이 그대로라면 1로, 아니라면 0으로 출력한다.
2. 주어진 숫자를 2의 거듭제곱인 숫자로 나눈 몫을 구할 때
다음 2진수로 표현된 예시를 살펴보자.
10진수 기준 20 : 2진수 8비트로 표현 시 00010100
이를 8로 나눈 몫을 구하고 싶다면 우측으로 3칸 비트를 이동시키면 된다.(>>3)
앞쪽에 없어지는 숫자들은 모두 부호가 같은 0으로 채워지므로 8비트로 표현 시 00000010(2)로 몫을 구할 수 있다.
3. 주어진 숫자를 2의 거듭제곱인 숫자로 나눈 나머지를 구할 때
8로 나눈다고 가정하면 우측에서 3개의 비트의 합이 곧 나머지가 됨을 알 수 있고, 이를 구하기 위해 위에서 학습한 &비트연산자를 활용하여 111(7)과 연산을 시켜주면 1인 비트들만 살아남아 나머지를 계산해낼 수 있다.
매우 생소하지만 때로는 강력한 연산자인 XOR연산자이다.
이는 같은 숫자면 0으로 다른 숫자면 1로 출력을 해주는 구조이다.
이 역시 조금 깊이 생각을 해보면 비트를 반전시키는 데에 효과적으로 사용을 할 수 있다.
다음 2진수로 표현된 예시를 살펴보자.
10진수 기준 20 : 2진수 8비트로 표현 시 00010100
10진수 기준 16 : 2진수 8비트로 표현 시 00010000
결과값: 00000100
위 2개의 수를 XOR 연산을 하게 되면 재미있는 현상이 벌어진다.
비트 기준으로 1이었던 수가 1과 XOR연산을 통해서 0으로 바뀌게 된다.
즉, 원하는 자리의 비트를 반전시키는 데에 매우 효과적으로 사용할 수 있다.
당연하게도 역으로 0이었던 숫자를 1로도 바꿀 수 있다.
다음 2진수로 표현된 예시를 살펴보자.
10진수 기준 20 : 2진수 8비트로 표현 시 00010100
10진수 기준 32 : 2진수 8비트로 표현 시 00100000
결과값:00110100
세 번째 자리수가 0에서 1로 바뀌었음을 확인할 수 있다.
다음 글에서는 실제 실습문제와 함께 코드를 살펴보자!