내가 보려고 만든 CS지식

비트연산(bitwise operation)과 비트 마스킹(bit Masking)

study note 2025. 8. 2. 17:43
반응형

❰비트연산❱

-비트연산(bitwise operation), 비트 마스킹(bit Masking)에 대해 배워봅시다.

 

▶비트연산이란?

한 개 혹은 두 개의 이진수에 대해 비트 단위로 적용되는 연산을 의미 합니다.

이진수는0과 1로 이루어진 수를 의미합니다.

그리고, 컴퓨터는 모든 데이터를 내부적으로 0과1로 이루어진 이진수 형태로 표현하고 처리합니다.

또한, 0과 1은 이진수면서 비트(bit)이기도 합니다.

비트는 컴퓨터의 가장 작은 단위이며 컴퓨터는 이 비트단위를 전등의 스위치처럼 이용합니다.

0이라는 수는 전등이 꺼져있는 상태, 1이라는 수는 전등이 켜져 있는 상태를 의미합니다.

정확히 설명하면 디지털회로에서 트랜지스터를 통한 ON/OFF상태를 의미합니다.

그리고 이 가장 작은 단위이자 스위치를 조작하거나 비교하는 걸 비트 연산이라고 하는 겁니다.

▶비트연산의 특징

①매우 빠르다(Extremely Fast)

CPU가 직접, 그리고 가장 기본적인 수준에서 처리하는 연산입니다. 덧셈이나 곱셈 같은 다른 복잡한 수학 연산보다 훨씬 빠르며

컴퓨터 하드웨어의 논리 게이트(Logic Gate) 수준에서 직접 구현되기 때문에, 프로그램 성능을 최적화해야 하는 상황에서 자주 사용됩니다. 아주 단순한 스위치를 켜고 끄는 것만큼 빠르다고 생각하시면 됩니다.

✿논리게이트란?
지금은 짧게 설명하고 나중에 추후 따로 정리하겠습니다.
논리 게이트는 디지털 회로의 가장 기본적인 구성 요소이며, 0과 1을 가지고 연산하는 모든 작업이 이 논리 게이트를 통해 이루어진다고 생각하시면 됩니다.

② 효율적인 공간 활용 (Efficient Memory Usage)

정보를 비트 단위로 다루기 때문에, 메모리나 저장 공간을 매우 효율적으로 사용할 수 있습니다. 예를 들어, 여러 개의 '예/아니요' 상태(Boolean flags)를 저장할 때, 각각 1바이트씩 할당하는 대신 하나의 바이트 안에 8개의 '예/아니오' 상태를 비트별로 저장할 수 있습니다. 이는 특히 메모리가 제한적인 임베디드 시스템이나 대용량 데이터를 처리할 때 중요합니다.

✿임베디드 시스템이란?
특정 목적을 수행하기 위해 기계나 장치 속에 '내장(embedded)'되어 있는 컴퓨터 시스템을 의미합니다. 일반적인 PC처럼 다양한 용도로 쓰이는 것이 아니라, 하나 또는 몇 가지의 정해진 기능을 효율적으로 수행하도록 설계된 컴퓨터 라고 할 수 있습니다. 자세한 정리는 추후  따로 하겠습니다.

➂ 하드웨어 제어 및 저수준 프로그래밍 (Hardware Control & Low-Level Programming)

하드웨어와 직접 소통하거나 제어할 때 필수적으로 사용됩니다. 특정 장치의 레지스터(Register)에 값을 쓰거나 읽을 때, 원하는 기능만 켜고 끄기 위해 비트 마스킹(Bit Masking) 같은 기법을 사용합니다. 운영체제 개발, 디바이스 드라이버 작성, 임베디드 시스템 프로그래밍 등 낮은 수준의 프로그래밍에서 매우 중요합니다.

➃ 특정 데이터 조작 (Specific Data Manipulation)

숫자 전체를 바꾸는 것이 아니라, 숫자를 구성하는 특정 비트만 켜거나 끄거나, 상태를 반전시키거나, 위치를 옮기는 등 매우 정밀한 데이터 조작이 가능합니다. 이는 데이터 압축, 암호화, 이미지 처리 등에서 특정 패턴을 만들거나 데이터를 효율적으로 변환하는 데 활용됩니다.

➄ 논리적 특성 활용 (Leveraging Logical Properties)

비트 연산은 수학적인 계산보다는 논리적인 판단(AND, OR, XOR, NOT)에 가깝습니다. 이러한 논리적 특성을 활용하여 특정 조건을 검사하거나, 복잡한 플래그(Flag) 상태를 관리하는 데 사용됩니다. 예를 들어, 어떤 권한들이 활성화되어 있는지 확인하거나, 여러 상태 중 특정 상태만 변경할 때 유용합니다.


▶비트연산자의 종류 및 예시

①AND (논리곱)

AND 연산두 비트(0, 1)와 모두 1일 때만 결과가 1이 되고 나머지는 모두 0이 됩니다

쉽게 말해, 두 비트의 값이 1의 전기신호를 받아야 ON상태가 되고 하나라도 0이면 OFF상태로 남게 됩니다.

특정 비트가 켜져 있는지 확인할 때 유용합니다. 예를 들어, 어떤 스위치 묶음에서 특정 스위치만 켜져 있는지 확인할 때 사용합니다.

사용 기호는 수학적/논리적/이론적 표기를 할 때는 ⋅ 또는 ∧ 

프로그래밍 언어에서는 & 를 사용하시면 됩니다.

A B A AND B
0 0 0
0 1 0
1 0 0
1 1 1

위의 표를 예로 들 수 있지만 0101이라는 비트 패턴과 0011이라는 패턴을 AND연산한다면, 각 자리를 비교해서 동시에 1인곳만 1이 됩니다.

예제를 보시면 0001이라는 결과 값이 나오는데 계산법은

첫 번째 자리는 첫번째 자리 0,0 = 0

두 번째 자리는 두번째 자리 1,0 = 0

세 번째 자리는 세번째 자리 0,1 = 0

네 번째 자리는 네번째 자리 1,1 = 1

이렇게 각 지정 자리마다 값을 더해줘 0001이라는 단위가 나오는 것입니다.

그럼? 이 논리곱으로 보면 ON상태일까 OFF상태일까 의문이 드시는 분도 계실 텐데 

각 자리마다 1개의 트랜지스터가 있다고 보시면됩니다. 

0(꺼짐), 0(꺼짐), 0(꺼짐), 1(켜짐) 총 4개의 트렌지스터 중 1개만 ON상태라고 보시면 됩니다.

 

➁OR(논리합)

OR연산두 비트(0,1) 중 하나라도 1이면 결과가 1이 되는 연산입니다.

특정 비트를 강제로 1로 만들거나, 여러 옵션 중 하나라도 활성화되어 있는지 확인할 때 사용합니다.

사용기호는 수학에서는 또는

A B A OR B
0 0 0
0 1 1
1 0 1
1 1 1

표를 보시면 하나라도 1이면 1로 계산이 되는 게 논리합이고 쉽게 말하면 덧셈입니다.

계산법은 각 자리마다 계산하면 되고 동일하게 4개의 트랜지스터로 보시면 됩니다.

 

➂NOT(논리 부정)

NOT연산0이 입력되면 1을 1이 입력되면 0이 나오는 입력 값이 반대가 되는 연산입니다

비트 패턴을 반전시키거나, 음수를 표현할 때 보수(complement)를 계산하는 데 사용합니다.

사용 기호는 ¬ 또는 Ā이며 프로그래밍 언어에서는 ~A로 사용됩니다.

A NOT A
0 1
1 0

위 표를 보시면0과 1로만 이루어져 있는데 입력에 있어서 피연산자 한 개만 필요하기 때문에 0,0과 1,1 같은 입력 조합이 없습니다.

계산법은 0은 1로 1은 0으로 변환하여 계산해주시면 됩니다.

동일하게 4개의 트랜지스터로 보시면 됩니다.

④XOR(배타적 논리합)

두 비트(0,1)의 입력값이 서로 다를 때만 출력이 1이 되며 두 입력값이 같으면 0으로 출력하는 연산입니다.

데이터 암호화, 오류 검출, 특정 비트를 효율적으로 뒤집을 때 사용돼요. XOR 연산을 두 번 하면 원래 값으로 돌아오는 특징 때문에 많이 활용됩니다.

사용기호는 ⊕이며 프로그래밍 언어에서는 ^ 를 사용합니다.

A B A XOR B
0 0 0
0 1 1
1 0 1
1 1 0

위 표를 보시면 같은 값은 0이 되고 서로의 값이 다르면 1로 출력되는 걸 확인하실 수 있습니다.

계산법은 0,0 =0으로 1,1= 0으로 0,1= 1로 변환하여 계산해주시면 됩니다.

동일하게 4개의 트랜지스터로 보시면 됩니다.

 

⑤시프트 연산(비트 이동, 왼쪽 시프트)

왼쪽 시프트 연산은 비트들을왼쪽으로 밀어내는 연산입니다. 마치 숫자에 0을 붙여 자릿수를 바꾸는 것과 같습니다.

비트들을 왼쪽으로 밀어주며 한 칸 밀면 를 곱하는 효과가 나옵니다.

0010이라는 연산 해보겠습니다. 0010을 한 칸 밀면 0010<< 1 = 0100이라는 값이 나오며 2를 곱하는 효과가 나온다는 말은 

십진수로 변환하였을 때 0010이면 십진수 2인데 0100이 됐으니 십진수 4가 된다는 말입니다.

또한 0010을 두 칸 미루게 되면  0010<< 2= 1000 이 되니까 십진수 8이라는 값이 나옵니다.

곱셈이나 나눗셈보다 훨씬 빠르게 의 거듭제곱으로 곱하거나 나눌 때 사용되며 효율적인 데이터 처리나 특정 비트를 빠르게 조작할 때 유용한 연산입니다

 

시프트 연산(비트 이동, 오른쪽 시프트)

오른쪽 시프트 연산은 비트들을 오른쪽으로 밀어내는 연산입니다. 마치 숫자에 0을 붙여 자릿수를 바꾸는 것과 같습니다.

비트들을 오른쪽으로 밀어주며 한 칸 밀면 로 나누는 효과가 나옵니다. (소수점 이하는 버려집니다)

1000을 오른쪽 시프트로 연산을 하면 1000>>1 = 0100이라는 십진수 4가 나옵니다.

다른 예제로 1001을 연산하면 1001>>1 = 0100이 되며 마지막 1은 오른쪽으로 밀리면서 1은 사라지게 됩니다.

이유는 정해진 비트수(예제에서 4bit)를 넘어서는 비트들은 사라지기 때문입니다.

✿단항연산자 : 입력(피연산자)이 한 개 만 필요합니다.(NOT)
✿이항연산자 : 입력(피연산자)가 두 개 필요한 연산입니다.(AND, OR, XOR)

 

비트연산에 대해 마쳤으니, 이제 비트 마스킹에 대해 배워보겠습니다.

 

▶비트 마스킹(Bit Masking)이란?

비트 마스킹은 비트 연산자(AND, OR, XOR, NOT, Shift 등)를 사용하여 어떤 숫자(데이터)의 특정 비트들을 '선택적으로' 조작하거나 그 상태를 확인하는 기술입니다.

쉽게 말해, 우리가 여러 개의 전등 스위치(비트)가 나란히 있는 스위치 패널을 가지고 있다고 상상해 봅시다. 이때, 내가 원하는 특정 위치의 스위치만 켜거나, 끄거나, 현재 켜져 있는지 확인하고 싶을 때 사용하는 방법이 바로 비트 마스킹입니다.

 

마스크(Mask)'의 역할

이름에 '마스킹'이 들어가는 것처럼, 이 기술의 핵심은 바로 '마스크(Mask)'라고 불리는 특별한 비트 패턴(숫자)입니다.

 

마스크: 조작하거나 확인하려는 비트의 위치를 지정해 주는 역할을 하는 이진수 패턴입니다.

마스크에서 1인 비트는 "이 위치의 비트에 주목해!" 또는 "이 위치의 비트를 조작할 거야!"라는 의미를 가집니다.

마스크에서 0인 비트는 "이 위치의 비트는 그대로 둬!" 또는 "이 위치의 비트는 신경 쓰지 마!"라는 의미를 가집니다.

쉽게 말해, 1은 강조 및 변경, 0은 유지 및 무시라고 생각하시면 됩니다.

 

'마스크'의 작동은 앞서 배운 비트 연산자들(AND, OR, XOR 등)과 함께 사용해서 원하는 비트만을 골라내어 작동합니다.

AND 연산을 사용하면 특정 비트가 켜져 있는지 확인할 수 있고, 특정 비트만 수도 있습니다.

OR 연산을 사용하면 특정 비트를 강제로 수 있습니다.

XOR 연산을 사용하면 특정 비트의 상태를 반전(토글)시킬 수 있습니다.

 

▶비트마스킹의 특징

비트 마스킹은 단순히 비트 연산을 응용하는 것을 넘어, 다음과 같은 실제 프로그래밍 상황에서 매우 중요하게 사용됩니다:

하드웨어 제어 : 마이크로컨트롤러, 센서 등 하드웨어 장치의 특정 기능(레지스터의 비트)을 켜고 끌 때 사용됩니다.

리소스 효율성: 여러 개의 ON/OFF 상태(예/아니오 플래그, 권한 설정)를 단 하나의 변수(예: 1바이트) 안에 압축하여 저장하고 관리할 때 사용됩니다. 이는 특히 메모리가 제한적인 환경에서 유용합니다.

데이터 조작: 데이터 압축, 암호화, 특정 비트의 빠른 변경 등 정밀하고 효율적인 데이터 처리에 활용됩니다.

간단히 말해, 비트 마스킹은 컴퓨터가 데이터를 가장 낮은 수준에서 정밀하고 빠르게 제어할 수 있도록 해주는 핵심 기술입니다.

 

▶비트마스킹의 활용을 알아보는 예제

10110110이라는 편의상 8bit의 이진코드가 있다고 하겠습니다. 이제 각 시나리오별로 비트 마스킹이 어떻게 사용되는지 예제로 확인해보겠습니다.

 

첫 번째, Check Bit로 AND 연산을 활용하여 특정 비트가 켜져 있는지 확인할 때입니다.

원본 데이터 10110110에서 2번 비트(오른쪽 0부터 세면 2번 비트, 10110110)가 1인지 확인하고 싶을 때 방법입니다.

AND 연산자를 사용하고 확인하고 싶은 비트 위치만 1로 만들고 나머지는 0인 마스크(00000100)를 만듭니다.

원본 데이터와 마스크를 AND연산합니다.

연산법은  논리곱 연산과 동일합니다. 마스크를 사용해 연산한다고 해서 논리게이트의 연산법이 바뀌는 건 없습니다.

 

두 번째, Set Bit로 OR연산을 활용 특정비트 켜기입니다.

원본 데이터 10100110에서 4번 비트(오른쪽 0부터 세면 4번 비트, 10100110)를 무조건 1로 만들고 싶을 때(0으로 만들고 싶어도 상관없습니다) OR연산자를 사용하고 켜고 싶은 비트 위치만 1로 만들고 나머지는 0인 마스크(00010000)를 만듭니다.

논리합 연산을 사용하여 연산하시면 됩니다.

 

세 번째, Clear Bit로 AND와 NOT연산을 조합하여 특정비트를 끄는 연산입니다.

원본 데이터 10110110에서 5번 비트(오른쪽 0부터 세면 5번 비트, 10110110)를 무조건 0으로 만들고 싶을 때

AND와 NOT을 조합하여 사용합니다. 끄고 싶은 비트 위치만 1로 만들고 나머지는 0인 임시 마크스를 만듭니다.

(00100000), 00100000(임시마스크)을 NOT연산으로 반전하면11011111됩니다. (이것이 실제 사용될 마스크입니다.) 

왜 XOR연산을 사용 안 하고 AND+NOT의 조합을 사용하냐 라는 의문이 드실 수 있는데 

그 이유는 확정적으로 꺼진다 즉, 실수로 다시 눌러도 꺼진 상태를 유지하기 위해 AND+NOT연산을 사용하는 것입니다.

즉, 무조건 꺼짐을 고정하는 스위치의 역할 반대로 위에 설명한 OR연산은 무조건 켜지는 스위치로 이해할 수 있습니다. XOR은 한 번 누르면 상태가 반전되고, 두 번 누르면 원래 상태로 돌아가는 특성이 있어, 스위치를 누를 때마다 ON/OFF가 반복되는 구조라고 이해하시면 됩니다.

마스크 값만 not으로 변경해 주시고, and연산을 활용해 계산해 주시면 되겠습니다.

 

네 번째, Toggle Bit로 XOR연산자를 이용한 특정 비트'반전(토글)'하는 연산입니다.

원본 데이터 10110110에서  0번째 비트(오른쪽에서 0부터 세면 0번째 비트, 10110110)의 상태를 반전시키고 싶을 때 (0이면 1로 1이면 0으로)

XOR연산자를 사용합니다. 반전시키고 싶은 비트 위치만 1로 만들고 나머지인 0인 마스크(00000001)를 만들면 됩니다.

xor연산을 활용해 비트를 반전시켜주시면 되겠습니다.

 

이것으로 비트 연산 및 비트 마스킹에 대해 마치겠습니다~

고생하셨습니다.😄

반응형