C

[C] Bitwise 연산자

ruming 2021. 5. 19. 07:19

평소 잘 이해가 안됐던 bitwise 연산자에 대해 정리해보도록 하겠다.

 

shift 연산자

>>

<<

 

AND, OR, XOR 연산자

&

|

^

 

NOT 연산자 (Unary operator)

~

 

※ Bitwise 연산자는 정수 타입에서만 사용할 수 있다. 

 

 

<<

  • 자릿수를 왼쪽으로 옮기는 기능을 한다. (넘어가는 자리 수는 무시)
  • i << j는 i를 이진법으로 표현했을 때 자릿수를 j만큼 왼쪽으로 옮긴다. (원래 i의 왼쪽 j개 비트는 없어진다.)
  • 부호가 변하지 않는 한 2^j배 한 효과가 있다.
i = 2017;
j = i << 2; //j = 8068

i = 00000000 00000000 00000111 11100001

j = 00000000 00000000 00011111 10000100

 

2^2 = 4, i의 4배한 값이 j가 된다.

 

>>

  • 자릿수를 오른쪽으로 옮기는 기능
  • 왼쪽은 sign bit로 채워진다. (양수이면 0, 음수이면 1이 채워짐)
  • 2^j로 나눈 효과
i = 2017;
j = i >> 2; // j=504

2017/4 = 504

 

비트연산자는 다른 산술 연산자보다 우선순위가 낮다.

*나 /연산자보다 연산 속도가 좋다. 

 

 

&, |, ^, ~

a & b   // 이진수 표현에서 각 자리가 둘 다 1이면 1

a | b    // 자리가 둘 다 0이면 0

a ^ b  // 자리가 같으면 0, 다르면 1

~a     // 0과 1을 서로 바꾼 값

 

연산결과

연산자 비트1 비트2 결과
& 0 0 0
0 1 0
1 0 0
1 1 1
| 0 0 0
0 1 1
1 0 1
1 1 1
^ 0 0 0
0 1 1
1 0 1
1 1 0

 

 

코딩도장 c코드를 첨부한다.

링크

#include <stdio.h>
 
int main()
{
    unsigned char num1 = 1;    // 0000 0001
    unsigned char num2 = 3;    // 0000 0011
 
    printf("%d\n", num1 & num2);    // 0000 0001: 01과 11을 비트 AND하면 01이 됨
    printf("%d\n", num1 | num2);    // 0000 0011: 01과 11을 비트 OR하면 11이 됨
    printf("%d\n", num1 ^ num2);    // 0000 0010: 01과 11을 비트 XOR하면 10이 됨
 
    return 0;
}

 

 

복합 연산자

+=, -=처럼 사용가능하다.

<<=, >>=, &=, |=, ^=

 

활용법

이진법 구성을 바꾸거나 확인

 - 각 자리 정하기

 - 각 자리에 저장된 값 확인하기

두 개의 변숫값 서로 바꾸기

2의 거듭제곱으로 나눈 나머지 판별

 


 

각 자리 정하기

  • 1로 정할 때는 |=, 0으로 정할 때는 &=연산자를 사용

1) i = 2017 (11111100001)에서 오른쪽에서 3번째 비트만 1로 바꾸고 싶을 때

i |= 4; 또는 i |= 0x4;  //i=2021(11111100101)

 

2) i의 오른쪽에서 8번째 비트만 0으로 바꾸고 싶을 때

i &= 0xFFFFFF7F; 또는 i &=~0x80;  //i=1893(11101100101)

 

3) i의 오른쪽에서 j번째 비트만을 1또는 0으로 바꾸기 

i |= (1 << (j-1));   //1으로 바꿈
i &= ~(1 << (j-1));   //0으로 바꿈

 

4) i의 오른쪽에서 연속 j개 bit만을 1로 정하기

i |= ((1 << j) - 1); 또는 i |= ~(-1 << j);

 

5) i의 오른쪽에서 연속 j개 bit만을 0으로 정하기

i &= ~((1 << j) - 1); 또는 i &= (-1 << j);

 

6) i의 왼쪽에서 연속 j개 bit만을 1로 정하기 (char형이면 32대신 8을 씀)

i |= (-1 << (32 - j));

 

7) i의 왼쪽에서 연속 j개 bit만을 0으로 정하기 (char형이면 32대신 8을 씀)

i &= ~(-1 << (32 - j)); 

 

각 자릿수 확인하기

 

1) i의 오른쪽에서 j번째 비트를 확인

i & (1 << (j-1))

1이면 위의 값이 0이 아니고, 0이면 0이다.

 

2) i의 연속된 j개의 비트 확인

오른쪽 j개 비트

i & ~(-1 << j) 또는 i & ((1 << j) - 1)

왼쪽 j개 비트 (char형이면 8)

i & (-1 << (32 - j))

 

3) 2의 거듭제곱으로 나눈 나머지 판별

if(i & 1){
 // case for odd number
}
else{
 // case for even number
}

 

switch(i & 3){
case 0:
 // case for i = 4k
case 1:
 // case for i = 4k + 1
case 2:
 // case for i = 4k + 2
case 3:
 // case for i = 4k + 3
}

 

a와 b의 값 바꾸기

a ^= b;
b ^= a;
a ^= b;

XOR을 이용해 두 변숫값을 바꿀 수 있다.

이건 유용하게 쓰일 것 같다.