비트 연산은 비트 단위에서 수행되는 연산이다. 기본 자료형 char, int와 같은 바이트 단위보다 더 작은 비트 단위를 다룬다. 정수형 변수 또는 정수형 값을 이루는 모든 비트들에 대해서 연산을 수행한다. (비트 연산자의 피연산자는 정수형 변수 또는 정수형 값이다.)
컴퓨터가 2진수를 사용하기 때문에 비트 연산은 일반적인 연산에 비해서 속도가 빠르고 메모리 사용이 효율적이다. 이러한 장점으로 MCU에서 작동하는 펌웨어 코드를 짤 때 많이 사용된다.
비트 연산자는 아래 표와 같이 &
, |
, ^
, ~
, <<
, >>
6가지가 있다.
사실 몇가지 더 있는데, 내가 쓸 일은 없을 것 같다.
되게 진부하지만 진리표는 아래와 같다.
^
기호를 쓰는 XOR 연산은 두 입력값이 다를 때, 결과값이 1이다.
AND 연산으로 비트 연산의 예를 보자.
int a = 0x12345678;
int b = 0xFF;
int result;
result = a & b;
메모리의 상태를 나타낼 때, 8자리를 2자리로 압축해서 나타낸다. (2진수를 16진수로)
16진수 한 자리는 2진수 네 자리에 대응된다. (1byte = 8bit = 16진수 두 자리)
mask 연산은 비트들 중에서 특정 비트를 마음대로 뽑아낼수 있게 한다.
아래 예시처럼 원하는 자릿수에 1을 넣어서 AND 연산을 수행하면 원하는 부분만 추출할 수 있다.
0인 비트를 1로 치환할 수 있게 한다.
입력값을 생각하지 않더라도 원하는 위치에 1을 넣어서 OR 연산하면 해당 위치는 1이 된다.
말 그대로 두 이진수 값을 비교할 수 있다.
결과값은 같으면 0, 다르면 1로 출력된다. 결과값의 모든 비트가 0이면 두 값은 같다.
입력값과 그 값의 NOT 연산을 더하면 모든 비트가 1이 된다.
1의 보수가 구해지므로 NOT 연산 수행 후에 1을 더하면 2의 보수를 구할 수 있다.
shift 연산은 2진수를 한 자리씩 원하는 방향으로 밀 수 있다.
왼쪽 shift를 두 번 수행하면 아래 예시와 같다.
왼쪽 shift는 2진수에서 자릿수가 하나씩 올라가는 것이므로 2를 곱하는 것과 같다. 10진수에서 자릿수를 올리기 위해서 10을 곱해야 하는 것과 같은 원리다. 주어진 입력값의 표현 범위를 벗어나면 상위 비트에 있던 값들은 사라진다. 최하위 비트는 한 칸씩 밀릴 때마다 계속해서 0이 채워진다.
반대로 오른쪽 shift는 2를 나누는 것과 같다. 왼쪽 shift와 달리 최상위 비트는 부호에 맞춰서 채워진다. 따라서 unsigned 자료형이면 최상위 비트는 무조건 0으로 채워진다.
16진수로 비트 연산을 수행할 경우 16진수를 직관적으로 받아들이기 쉽지 않으므로
0x02
보다는 0x01 << 1
로 표현하는 것이 가독성이 더 좋다.
- 상수식은 컴파일 할 때 계산된다. 실행 시간에 연산이 수행되지 않으므로 성능에 영향이 없다.
- 일반 곱하기 연산보다 shift 연산이 속도가 더 빠르지만 가독성이 떨어진다.
shift 연산은 하드웨어 제어에서 많이 쓰이는데
LED를 제어하기 위해서 한 칸씩 이동한다든지, FND에서 숫자를 이동시킬 때 사용해보았다.