이번 단원에서는
1. 부호 있는 정수와 부호 없는 정수 두 자료형에 비트 연산을 했을 때 어떤 차이점이 있는지 알아 볼 것이다.
2. 또한 비트 연산자를 응용한 플래그 처리 방법도 알아볼 것이다.
시프트 연산과 2의 거듭제곱 알아보기
시프트 연산자는 2의 거듭제곱인 숫자를 빠르게 구할 때 유용하다.
char형은 1바이트(8비트)이고 이에 따라 총 8개의 0과 1을 적을 수 있다.
2진수이기 때문에 1을 왼쪽으로 한 자리씩 시프트하면 그에 따른 제곱이 하나씩 올라가
시프트 연산자를 통해 거듭제곱인 숫자를 빠르게 구할 수 있다. 즉 비트의 이동 횟수는 지수(exponent)와 같다.
시프트 연산으로 자릿수를 넘어서는 경우 알아보기
시프트 연산자를 사용하여 비트가 첫째 자리나 마지막 자리를 넘어설 때까지 이동하면 어떻게 될까??
코드에서 주석을 달아놓은 것 처럼 연산이 되어 나왔다.
부호 있는 자료형의 비트 연산 알아보기
위에서는 부호 없는(unsigned) 자료형으로 비트연산을 했다.
하지만 부호 있는 자료형을 비트 연산할 때에는 조심해야 한다.
먼저 부호 없는 자료형과 부호 있는 자료형에 >> 연산을 해보자.
※ 부호있는 자료형의 첫번째 비트는 부호 비트라고 하는데 이 비트가 1이면 음수, 0이면 양수이다.
코드에서 주석을 단 대로, signed와 unsigned는 비트 연산에서 다르게 적용한다.
signed에서 첫 번째 비트는 부호 비트로써 작용하고 1일 경우 그 값은 음수이다.
signed을 놓고 설명하자면 첫 번째 비트가 1일 경우, -128(-2^7)의 값을 가지고 있다.
위의 코드는 1111 1100이다.
첫 비트를 제외한 비트들은 양수의 값을 가지기 때문에
정수 서식 지정자로 프린트할 경우 (-128) + 64 + 32 + 16 + 8 + 4 = -4 가 된다.
부호 있는 자료형에서 부호 비트가 0인 양수에 >> 연산을 하면 어떻게 될까?
부호 있는 자료형에서 << 연산을 해보자.
비트가 움직이는대로 덧씌워진다. 결국 중요한 것은 signed의 경우, 첫 비트를 유심히 보아야 한다는 것이다.
비트 연산자로 플래그 처리하기
플래그(flag)는 깃발에서 유래한 용어이다. 보통 깃발을 위로 올리면 on, 아래로 내리면 off를 뜻한다.
이것을 정수의 비트에 활용하는 것인데, 비트가 1이면 on, 0이면 off를 나타낸다.
8비트(1바이트)의 크기 자료형은 비트 8개가 들어가므로 8가지 상태를 저장할 수 있다.
회색 바탕의 설명에서는 두번째 비트와 여덟번째 비트가 켜진 상태!!
0100 0001 // 두 번째 비트와 여덟 번째 비트가 켜진 상태(on)
int와 같은 4바이트 크기의 자료형은 32비트이므로 32개의 상태를 저장할 수 있다.
플래그는 적은 공간에 정보를 저장하거나, 빠른 속도가 필요할 때 사용한다. 플래그를 사용하는 대표적인 장치는 CPU인데, CPU는 내부 저장 공간에 매우 작으므로 각종 상태를 비트로 저장한다.
특정 비트를 켜는 방법은
플래그 |= 마스크 이다.
플래그로 사용할 변수에 |= 연산자와 숫자를 사용하여 특정 비트를 켠다.
여기서 플래그의 비트를 조작하거나 검사할 때 사용하는 숫자를 마스크(mask)라고 한다.
비트연산자 OR(|)을 이용해 플래그를 켰다.
OR 연산은 하나만 1이여도 참의 값을 반환한다.
논리연산 OR에서는 0과 1은 1이다. 1과 1도 1이다.
따라서 0인 경우는 1로 플래그를 켤 수 있고, 1인 경우는 그냥 1로써 유지가 가능하다.
또, 비트연산자 AND(&)를 이용해 특정 비트가 켜져있는지 확인했다.
논리연산 AND에서는 두 비트가 모두 1이여야 1이다.
따라서 위의 flag에 저장된 0000 0111과
마스크 값 0000 0100을 &로 연산하면 여섯번째 비트가 1이 된다.
0000 0111 (&)
0000 0100
= 0000 0100 (6번째 비트가 켜져 있는 것 확인 가능)
다음은 플래그의 비트를 끄는 방법이다.
플래그 &= ~마스크
마스크 값을 ~ 연산자로 비트를 싹 뒤집은 뒤, &= 연산자를 통해 특정 비트를 끈다.
기존 0000 0111 비트에서
플래그 ~2는 1111 1101 이 된다 (플래그 2의 값은 0000 0010이기 때문이다.)
0000 0111 (&)
1111 1101
= 0000 0101
= 5
마지막으로, 비트가 켜져있다면 끄고, 꺼져있다면 켜는 방법이다.
이러한 기능을 토글(toggle)이라고도 한다.
플래그 ^= 마스크
^= 연산자를 이용해 특정 비트가 켜져있으면 끄고 꺼져있으면 켠다.
^는 배타적 OR으로, 두 비트가 다르다면 1, 같으면 0이다. flag의 비트가 1이라면 마스크의 1과 같을 때는 0이 되고, 0이라면 마스크의 1과 다르므로 1이 되는 원리이다.
비트연산자의 고급 사용 방법이라고 한다. 내용이 복잡하기도 하고 쓰이는 곳이 많지는 않지만
나중에 리눅스 커널의 소스코드를 보거나 하드웨어를 다룰 때 사용할 것이다.
심사문제: 시프트 연산과 플래그 활용하기
컴파일 화면을 보시려면 더보기를 클릭하세요!
'C, C++' 카테고리의 다른 글
C언어 코딩도장(for 반복문) (0) | 2022.04.27 |
---|---|
C언어 코딩도장(switch 분기문) (0) | 2022.04.27 |
오늘 공부한 C언어(비트 연산자 이용하기) (0) | 2022.03.09 |
오늘 공부한 C언어(불 자료형 사용하기) (0) | 2022.03.09 |
오늘 공부한 C언어(논리 연산자 사용하기) (0) | 2022.03.06 |