본문 바로가기
C,C++/Etc

[C++] 비트 연산자로 N번째 비트 변경하기

by woohyeon 2020. 3. 11.
반응형

비트 연산자로 N번째 비트 변경하기


비트 단위로 연산을 수행하는 비트 연산자를 통해 원하는 비트 자리 수를 간단하게 변경하는 방법을 알아보자.


[비트 연산자]


여기서 사용할 연산자만 소개

  • |   (OR)
  • & (AND)
  • ~ (NOT)
  • << (left shift)
  • >> (right shift)


1바이트 짜리 unsigned char 타입을 통해 비트 연산을 해보자. 먼저 1바이트는 8비트로 true/false의 값을 8개 저장할 수 있다.

다음과 같이 unsigned char 타입의 변수를 0으로 초기화 후 bitset 클래스를 통해 이진수 형식으로 출력해보자.
bitset 클래스는 <bitset> 헤더 파일을 include 해야한다.

#include <bitset>
#include <iostream>

void main()
{
   unsigned char c = 0;
   
   std::cout << std::bitset<8>(c) << std::endl;
}


bitset 클래스는 템플릿 매개변수로 출력을 원하는 비트 수를 받는다. 위의 코드는 c를 8비트로 출력한다.
따라서 위 결과는 0을 이진수로 표현한 0000 0000으로 나올 것이다. (여기선 가독성을 위해 4칸마다 띄어쓰기)




[첫 번째 비트 0을 비트 1로 만들기]

그럼 c의 첫 번째 비트를 1로 set 하고 싶다고 생각해보자. 즉 0000 00000000 0001로 만들고 싶다.
0을 1로 변경하기 위해선 OR이라는 비트 연산을 통해 얻어내야 한다. 0과 1을 OR 연산하면 1이 되는 성질을 이용한다. 나머지 비트는 모두 0으로 유지한다.   

#include <bitset>
#include <iostream>

void main()
{
   unsigned char c = 0;
   
   c |= 1; // 0000 0000 OR 0000 0001
   std::cout << std::bitset<8>(c) << std::endl; // 0000 0001
   
}


[두 번째 이상 비트를 비트 1로 만들기]

나머지 비트는 그대로 유지하고, 두번째 비트를 1로 만들기 위해선 0000 0010 을 OR 연산해주어야 한다.
0은 OR연산을 하더라도 기존 비트 값을 그대로 유지하기 때문에 원하는 비트를 제외한 나머지 비트는 모두 0이여야 한다.

0000 0010은 1을 1만큼 left-shift 연산을 수행하면 된다. shift 연산은 원하는 방향으로 모든 비트를 이동시킨다.
따라서 아래와 같이 1을 왼쪽으로 1 shift하여 c와 OR 연산을 해주면 두번째 비트가 1로 set된다. 

#include <bitset>
#include <iostream>

void main()
{
   unsigned char c = 0;
   
   c |= 1; // 0000 0000 OR 0000 0001
   c |= (1 << 1) // 0000 0001 OR 0000 0010
   
   std::cout << std::bitset<8>(c) << std::endl; // 0000 0011
}


위의 결과만으로도 n번째 비트를 1로 set하기 위해선 얼마만큼 shift 연산을 하여 OR연산을 해야하는지 이해할 수 있을 것이다.



[첫 번째 비트를 0으로 만들기]

이번엔 위에서 변경한 c의 첫 번째 비트와 두 번째 비트를 다시 0으로 만들어보자. 1은 단순히 원하는 비트만 1로 만든 후 c와 OR연산을 해주면 됐지만, 0으로 만들기 위해선 AND연산이 필요하다. AND는 기존 비트에 영향을 주지 않으려면 0으로 만드려는 비트를 제외한 모든 비트가 1이여야 한다. 예를 들어 11의 첫 번째 비트만 0으로 만들고 싶다면 10과 AND연산을 해야한다.

0000 0011을 0000 0010으로 만들기 위해선 1111 1110과 AND연산을 해야한다.
1111 1110은 역으로 생각해보면 0000 0001의 모든 비트를 NOT(~) 연산을 하여 각 비트를 뒤집은 수이다. 따라서 다음과 같이 1을 NOT 연산 후 c와 AND 연산을 해준다.

#include <bitset>
#include <iostream>

void main()
{
   unsigned char c = 0;
   
   c |= 1;        // 0000 0000 OR 0000 0001
   c |= (1 << 1); // 0000 0001 OR 0000 0010
   
   c &= ~(1 << 0); // 0000 0011 AND 1111 1110
   
   std::cout << std::bitset<8>(c) << std::endl; // 0000 0010
}

 


[두 번째 비트를 0으로 만들기]

이번엔 두 번째 비트를 0으로 만들어보자. 이전과 동일하게 0000 0010의 두 번째 비트를 0으로 만들기 위해선 두 번째 비트를 제외한 모든 비트가 1인 수와 AND연산을 하면된다.

1111 1101은 NOT 연산을 하면 0000 0010이 된다. 즉 1을 1만큼 left-shift 후에 NOT 연산을 하면 1111 1101이 된다.
이 후 c와 AND 연산을 하면 원하는 두 번째 비트가 0이 된다.

#include <bitset>
#include <iostream>

void main()
{
   unsigned char c = 0;
   
   c |= 1;        // 0000 0000 OR 0000 0001
   c |= (1 << 1); // 0000 0001 OR 0000 0010
   
   c &= ~(1 << 0); // 0000 0011 AND 1111 1110
   c &= ~(1 << 1); // 0000 0010 AND 1111 1101
   
   std::cout << std::bitset<8>(c) << std::endl; // 0000 0000
}


여기까지 간단한 비트를 계산법을 알아봤고, 지금까지의 내용을 이해했다면 원하는 자릿수도 제어할 수 있을 것이다. 




댓글