반응형
출처 : Tips Soft
비트 연산자
대부분의 고급 프로그래밍 언어들이 변수의 최소단위를 비트가 아닌 바이트로 다루기 때문에
프로그램을 하다보면 메모리 낭비가 심할수 있습니다.
예를들어, 자신이 작성하는 프로그램에서 어떤 값을 저장시켜야 하는데 그 값이 0 또는 1의 값만
가진다고 가정해봅시다. 저장시켜야할 대상이 0 또는 1이라면 분명 1비트의 공간만 있으면 충분히 저장이
가능합니다. 하지만, 많은 프로그래밍 언어가 1비트 단위의 변수를 제공하지 않기 때문에 일반적인
최소단위인 1 바이트 변수에 정보를 저장하게 됩니다.
1 바이트는 8 개의 비트로 구성되기 때문에 결국 7비트는 낭비하게 되는 것입니다. 이러한 경우 비트
연산자를 사용하면 비트 단위로 정보를 관리 할 수 있습니다.
1. 비트합 ( A | B )
비트별로 연산한다는 점을 제외하면 연산규칙은 논리합이랑 동일합니다. 비트별 값을 연산하기
프로그램을 하다보면 메모리 낭비가 심할수 있습니다.
예를들어, 자신이 작성하는 프로그램에서 어떤 값을 저장시켜야 하는데 그 값이 0 또는 1의 값만
가진다고 가정해봅시다. 저장시켜야할 대상이 0 또는 1이라면 분명 1비트의 공간만 있으면 충분히 저장이
가능합니다. 하지만, 많은 프로그래밍 언어가 1비트 단위의 변수를 제공하지 않기 때문에 일반적인
최소단위인 1 바이트 변수에 정보를 저장하게 됩니다.
1 바이트는 8 개의 비트로 구성되기 때문에 결국 7비트는 낭비하게 되는 것입니다. 이러한 경우 비트
연산자를 사용하면 비트 단위로 정보를 관리 할 수 있습니다.
1. 비트합 ( A | B )
비트별로 연산한다는 점을 제외하면 연산규칙은 논리합이랑 동일합니다. 비트별 값을 연산하기
때문에 참/거짓이 아닌 0/1로 표현을 많이 합니다.
A (비트합) B -> (결과)
1(참) | 1(참) 1(참)
1(참) | 0(거짓) 1(참)
0(거짓) | 1(참) 1(참)
0(거짓) | 0(거짓) 0(거짓)
비트합 연산을 살펴보시면 알겠지만 두 비트중에 한 비트라도 1 이면 결과가 1이 됩니다. 반대로
A (비트합) B -> (결과)
1(참) | 1(참) 1(참)
1(참) | 0(거짓) 1(참)
0(거짓) | 1(참) 1(참)
0(거짓) | 0(거짓) 0(거짓)
비트합 연산을 살펴보시면 알겠지만 두 비트중에 한 비트라도 1 이면 결과가 1이 됩니다. 반대로
한쪽 비트가 0 이면 다른쪽 비트의 값이 그대로 결과 값이됩니다. 따라서 비트합 연산자를 사용하면
자신이 원하는 비트에 1 을 강제로 연산하여 해당 비트를 1로 만들수도 있습니다.
아래와 같이 data 라는 문자형 변수가 있습니다. 이 변수의 최상위비트(1 바이트로 가정, 가장 왼쪽에
아래와 같이 data 라는 문자형 변수가 있습니다. 이 변수의 최상위비트(1 바이트로 가정, 가장 왼쪽에
있는 비트)를 1로 설정하는 법을 설명하겠습니다.
// 16진수 17 값은 2진수로 표현하면 0001 0111 입니다.
char data = 0x17;
// 16진수 17 값은 2진수로 표현하면 0001 0111 입니다.
char data = 0x17;
// 16진수 80 값은 2진수로 표현하면 1000 0000 입니다. 최상위 비트를 1로 만들기 위해서
// 최상위 비트만 1인 수를 구성하면 그 값이 16진수로 0x80 이라는 뜻입니다.
char mask = 0x80;
char result = data | mask;
char mask = 0x80;
char result = data | mask;
// mask 변수가 최상위 비트를 제외한 나머지 7 비트를 모두 0 으로 설정했기 때문에
// 비트합 연산시에 data 의 7 비트 값이 그대로 결과 값이 됩니다.
data : 0 0 0 1 0 1 1 1
mask : 1 0 0 0 0 0 0 0
------------------------------
1 0 0 1 0 1 1 1 // 결과는 0x97 의 값이 됩니다. ( 10 진수로 151 입니다.)
비트합 연산자의 연산 특성상 자신이 1로 만들고 싶은 비트에 1을 설정하여 연산하면 대상의 값이
data : 0 0 0 1 0 1 1 1
mask : 1 0 0 0 0 0 0 0
------------------------------
1 0 0 1 0 1 1 1 // 결과는 0x97 의 값이 됩니다. ( 10 진수로 151 입니다.)
비트합 연산자의 연산 특성상 자신이 1로 만들고 싶은 비트에 1을 설정하여 연산하면 대상의 값이
무엇이든간에 결과는 1이 됩니다. 따라서 최상위 비트는 무조건 1이 되고 나머지 비트들은 0으로
연산을 시켜서 본래의 값이 유지되도록 합니다.
2. 비트곱 ( A & B )
비트별로 연산한다는 점을 제외하면 연산규칙은 논리곱이랑 동일합니다. 비트별 값을 연산하기
2. 비트곱 ( A & B )
비트별로 연산한다는 점을 제외하면 연산규칙은 논리곱이랑 동일합니다. 비트별 값을 연산하기
때문에 참/거짓이 아닌 0/1로 표현을 많이 합니다.
A (비트곱) B -> (결과)
1(참) & 1(참) 1(참)
1(참) & 0(거짓) 0(거짓)
0(거짓) & 1(참) 0(거짓)
0(거짓) & 0(거짓) 0(거짓)
비트곱 연산을 살펴보시면 알겠지만 "두 비트중에 한 비트라도 0 이면 결과가 0"이 됩니다.
A (비트곱) B -> (결과)
1(참) & 1(참) 1(참)
1(참) & 0(거짓) 0(거짓)
0(거짓) & 1(참) 0(거짓)
0(거짓) & 0(거짓) 0(거짓)
비트곱 연산을 살펴보시면 알겠지만 "두 비트중에 한 비트라도 0 이면 결과가 0"이 됩니다.
반대로 한쪽 비트가 1 이면 다른쪽 비트의 값이 그대로 결과 값이됩니다. 따라서 비트합 연산자를
사용하면 자신이 원하는 비트에 0 을 강제로 연산하여 해당 비트를 0 으로 만들수도 있습니다.
아래와 같이 data 라는 문자형 변수가 있습니다. 이 변수의 최상위비트(1 바이트로 가정, 가장 왼쪽에
아래와 같이 data 라는 문자형 변수가 있습니다. 이 변수의 최상위비트(1 바이트로 가정, 가장 왼쪽에
있는 비트)를 0으로 설정하는 법을 설명하겠습니다.
// 16진수 87 값은 2진수로 표현하면 1001 0111 입니다.
char data = 0x87;
char data = 0x87;
// 16진수 80 값은 2진수로 표현하면 0111 1111 입니다. 최상위 비트를 0으로 만들기 위해서
// 최상위 비트만 0인 수를 구성하면 그 값이 16진수로 0x7F 라는 뜻입니다.
char mask = 0x7F;
// 최상위 비트만 0인 수를 구성하면 그 값이 16진수로 0x7F 라는 뜻입니다.
char mask = 0x7F;
char result = data & mask;
// 최상위 비트를 제외한 나머지 7 비트를 모두 1 으로 설정했기 때문에
// 비트곱 연산시에 data 의 7 비트 값이 그대로 결과 값이 됩니다.
data : 1 0 0 1 0 1 1 1
mask : 0 1 1 1 1 1 1 1
-------------------------------
0 0 0 1 0 1 1 1 // 0x17 의 값이 됩니다.
비트곱 연산자의 연산 특성상 자신이 0 으로 만들고 싶은 비트에 0을 설정하여 연산하면 대상의 값이
data : 1 0 0 1 0 1 1 1
mask : 0 1 1 1 1 1 1 1
-------------------------------
0 0 0 1 0 1 1 1 // 0x17 의 값이 됩니다.
비트곱 연산자의 연산 특성상 자신이 0 으로 만들고 싶은 비트에 0을 설정하여 연산하면 대상의 값이
무엇이든간에 결과는 0 이 됩니다. 따라서 최상위 비트는 무조건 0 이 되고 나머지 비트들은 1 로
연산을 시켜서 본래의 값이 유지되도록 합니다.
결국 같은 의미이겠지만 비트곱은 자신이 원하는 비트를 0 으로 만드는것 외에 또다른 용도로도
결국 같은 의미이겠지만 비트곱은 자신이 원하는 비트를 0 으로 만드는것 외에 또다른 용도로도
사용됩니다. 바로 자신이 원하는 비트값이 0 인지 1인지 확인할때 사용합니다.
"자신이 원하는 비트의 값이 0 인지 1 인지 확인할때도 비트곱을 사용합니다."
아래와 같이 data 라는 문자형 변수가 있습니다. 이 변수의 최상위비트(1 바이트로 가정, 가장 왼쪽에
"자신이 원하는 비트의 값이 0 인지 1 인지 확인할때도 비트곱을 사용합니다."
아래와 같이 data 라는 문자형 변수가 있습니다. 이 변수의 최상위비트(1 바이트로 가정, 가장 왼쪽에
있는 비트)가 0 인지 1 인지 확인하는 코드를 작성해 보겠습니다.
// 16진수 87 값은 2진수로 표현하면 1001 0111 입니다.
char data = 0x87;
char data = 0x87;
// 16진수 80 값은 2진수로 표현하면 1000 0000 입니다. 최상위 비트값을 알기 위해서
// 최상위 비트만 1인 수를 구성하면 그 값이 16진수로 0x80 라는 뜻입니다.
char mask = 0x80;
char result = data & mask;
if(result == mask) printf("최상위 비트는 1입니다.");
// 최상위 비트만 1인 수를 구성하면 그 값이 16진수로 0x80 라는 뜻입니다.
char mask = 0x80;
char result = data & mask;
if(result == mask) printf("최상위 비트는 1입니다.");
else printf("최상위 비트는 0입니다.");
// 최상위 비트를 제외한 나머지 7 비트를 모두 0 으로 설정했기 때문에
// 비트곱 연산시에 data 의 7 비트 값이 모두 0 이됩니다.
data : 1 0 0 1 0 1 1 1
mask : 1 0 0 0 0 0 0 0
------------------------------
1 0 0 0 0 0 0 0 // 0x80 의 값이 됩니다.
결론적으로 비트곱은 한쪽이 0 이면 무조건 0 이되기 때문에 자신이 관심이 없는 비트는 모두 0 으로
data : 1 0 0 1 0 1 1 1
mask : 1 0 0 0 0 0 0 0
------------------------------
1 0 0 0 0 0 0 0 // 0x80 의 값이 됩니다.
결론적으로 비트곱은 한쪽이 0 이면 무조건 0 이되기 때문에 자신이 관심이 없는 비트는 모두 0 으로
설정하고 관심이 있는 비트를 1로 설정해서 숫자를 구성한 후, 이 값을 특정 변수와 비트연산을
수행하면 그 결과가 0 이면 해당 비트가 0 이라는 뜻이고 0 아 아니라면 해당 비트가 1 이라는
뜻입니다. ( 결국 해당 비트가 1인 경우, 비트 연산을 시킨 mask 값과 결과 값이 동일하게 나옵니다. )
3. 비트부정 ( 단항연산자, ~A )
논리연산자 Not 이 진리값을 부정하였다면 비트연산자 ~ 는 비트별 하나씩을 부정하는 기능을 가지고
3. 비트부정 ( 단항연산자, ~A )
논리연산자 Not 이 진리값을 부정하였다면 비트연산자 ~ 는 비트별 하나씩을 부정하는 기능을 가지고
있습니다. 그렇다면 비트부정은 어디에 쓰일까요?
컴퓨터는 음수(뺄셈)에 관련된 회로가 없습니다. 그렇다면 어떻게 뺄셈을 수행할까요?
컴퓨터는 음수(뺄셈)에 관련된 회로가 없습니다. 그렇다면 어떻게 뺄셈을 수행할까요?
들어 보셨겠지만 컴퓨터는 "보수" 라는 개념을 이용하여 뺄셈을 수행할수 있습니다. 간단하게 예를
들어보겠습니다.
data 변수가 있고 이 변수가 8비트인 1 바이트 크기의 변수라고 가정하겠습니다.
모두 1로 구성되었다고 가정하겠습니다. ( 2진수로 1111 1111 이고 16진수로 0xFF 의 값입니다. )
이 값에 1을 더해보겠습니다. 어떻게 될까요?
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 1
-------------------------------
1 0 0 0 0 0 0 0 0
결과가 9 비트가 되었습니다. 결국 변수는 8 비트까지만 저장가능하기 때문에 가장 앞에 있는 1은
data 변수가 있고 이 변수가 8비트인 1 바이트 크기의 변수라고 가정하겠습니다.
모두 1로 구성되었다고 가정하겠습니다. ( 2진수로 1111 1111 이고 16진수로 0xFF 의 값입니다. )
이 값에 1을 더해보겠습니다. 어떻게 될까요?
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 1
-------------------------------
1 0 0 0 0 0 0 0 0
결과가 9 비트가 되었습니다. 결국 변수는 8 비트까지만 저장가능하기 때문에 가장 앞에 있는 1은
오버플로우(overflow) 되었다고 판단하여 버리게 됩니다. 결국 결과 값이 0 이 됩니다.
즉, 오버플로우 현상을 이용하면 0xFF 값을 0 으로 만들기 위해서 0xFF 값을 빼지 않고 단순히 1 을
더해서도 0 으로 만들수 있습니다.
위 예제에서는 설명을 편하게 하기 위해서 0xFF 값을 사용했기 때문에 쉽게 1을 더하면 0xFF를
뺀것과 같다라는것을 알았지만 0x32 값을 0으로 만들기 위해서 0x32를 빼지않고 얼마를 더해야지
0 이 될까요?
위와 같은 경우에 반대되는 숫자를 찾을수 있는 개념이 "보수"입니다. 우리가 흔히, 0 에 대한 1 의
보수가 1이고 1 에 대한 1의 보수가 0 이라고 합니다. 즉, 1 의 보수의 개념에서 보면 1 -> 0 이고
0 -> 1 입니다. 결국 Not 의 개념입니다. 그런데 이것이 진리값이 아닌 숫자값에 적용되어야 하기
때문에 비트부정(Bit Not)이 되는겁니다.
"비트부정을 사용하면 해당 값에 대한 1의 보수 값을 구할수 있습니다."
그러나 컴퓨터에서 뺄셈의 효과를 내는 덧셈숫자를 찾는데에는 2의 보수를 사용합니다. 이것은
"비트부정을 사용하면 해당 값에 대한 1의 보수 값을 구할수 있습니다."
그러나 컴퓨터에서 뺄셈의 효과를 내는 덧셈숫자를 찾는데에는 2의 보수를 사용합니다. 이것은
1의 보수보다 더 단순한 개념입니다. 2의 보수는 1의 보수값에 1을 더한 값입니다.
0xFF 의 1의 보수값이 얼마일까요? 0xFF를 2진수로 표현하면 1111 1111 이기 때문에 비트부정을
하면 0000 0000 이고 값이 0x00입니다. 이값에 1을 더하면 2의 보수가 된다고 했습니다.
그럼 0x01 입니다. 결국, 0xFF 에 대한 2의 보수값이 0x01 입니다.
위에서 하다만 0x32 에 대한 이야기를 계속하면 0x32는 2진수로 0011 0010 입니다. 이 값에 1의 보수를
위에서 하다만 0x32 에 대한 이야기를 계속하면 0x32는 2진수로 0011 0010 입니다. 이 값에 1의 보수를
취하면 1100 1101 입니다. (비트부정) 그리고 1의 보수값에 1을 더하면 2의 보수값이 됩니다.
더한 값은 1100 1110 이 됩니다. 이 값은 16진수로 0xCE 입니다. 결론을 내리면 아래 두 수식은
동일하다는 뜻입니다.
0x32 - 0x32 --> 0
0x32 + 0xCE --> 0
"어떤수에 N 값을 빼는것과 [N의 2의보수]를 더한것은 동일하다."
위 내용을 프로그램적으로 표현해보겠습니다. 아래의 data1 과 data2 변수는 동일한 값을 가집니다.
0x32 - 0x32 --> 0
0x32 + 0xCE --> 0
"어떤수에 N 값을 빼는것과 [N의 2의보수]를 더한것은 동일하다."
위 내용을 프로그램적으로 표현해보겠습니다. 아래의 data1 과 data2 변수는 동일한 값을 가집니다.
data1 = 0x37 - 0x32;
data2 = 0x37 + (~0x32 + 1); // 비트부정 -> 1의 보수,, 1의 보수 + 1 -> 2의 보수
4. 배타적 비트합 ( A ^ B )
배타적이라는 용어답게 이 연산자는 서로 같은 값을 가지면 0 이되고 다르면 1이 되는 연산자입니다.
A (비트합) B -> (결과)
1(참) ^ 1(참) 0(거짓)
1(참) ^ 0(거짓) 1(참)
0(거짓) ^ 1(참) 1(참)
0(거짓) ^ 0(거짓) 0(거짓)
배타적 비트합 연산자의 연산 특성은 특이해 보이지만 일정한 규칙을 가지고 있습니다. 즉, 특정
패턴에 동일한 패턴을 두번 연속 연산을 시키면 본래 자신의 값이 다시 나온다는 것입니다. 예를들어
보겠습니다.
0 1 0 1 1 1 0 0 // 기준 패턴
0 1 1 0 0 1 0 0 // Key 패턴
-------------------
0 0 1 1 1 0 0 0 // 새로운 패턴이 나옴.
0 1 1 0 0 1 0 0 // 다시 Key 패턴을 배타적 비트합으로 연산시킴
-------------------
0 1 0 1 1 1 0 0 // 기준 패턴
아시겠습니까? 이런 연산특성을 사용하여 간단한 암호화나 화면 갱신없이 빠르게 화면에 이동가능한
기준선을 그릴 수 있습니다.
반응형
'C & C++ > C & C++' 카테고리의 다른 글
유니 코드( Unicode ) 환경에서의 WM_COPYDATA 쓰레기 값 제거 (0) | 2014.04.29 |
---|---|
배열 요소의 크기 구하기 (0) | 2014.03.07 |
MS Office 파워 포인트 자동화(PPT Automation) (0) | 2013.11.15 |
MS Office( 엑셀, 워드, 파워포인터 ) 및 기타 프로그램 설치 여부 확인 (0) | 2013.11.14 |
SHBrowseForFolder 폴더 선택 다이얼로그 (0) | 2013.08.29 |
댓글