공부했던 자료 정리하는 용도입니다.
재배포, 수정하지 마세요.
비트 연산자
- 비트 연산자의 종류
- 시프트 연산
- 플래그(flag)와 마스크
- XOR 연산의 특성
비트연산자
비트 연산자는 비트로 옵션을 설정할 때 주로 사용하며 저장 공간을 아낄 수 있는 장점이 있다. 이와 같은 방식을 플래그(flag)라고 하며, 연산과 할당이 한꺼번에 이루어지는 연산자는 플래그를 켜거나 끌 때 유용하게 활용된다.
- bit : 2진수를 저장하는 단위. 컴퓨터에서 사용하는 최소 단위이며 0과 1을 나타낸다.
최상위 비트(Most Significant Bit, MSB) : 첫 번째 비트
최하위 비트(Least Significant Bit, LSB) : 마지막 비트 - byte : 8 bit 크기의 단위
■ 비트 연산자의 종류
연산자 | 설 명 |
& | 비트 AND |
| | 비트 OR |
^ | 비트 XOR(배타적 OR, Exclusive OR) |
~ | 비트 NOT |
<< | 비트를 왼쪽으로 시프트 |
>> | 비트를 오른쪽으로 시프트 |
&= | 비트 AND 연산 후 할당 |
|= | 비트 OR 연산 후 할당 |
^= | 비트 XOR 연산 후 할당 |
<<= | 비트를 왼쪽으로 시프트한 후 할당 |
>>= | 비트를 오른쪽으로 시프트한 후 할당 |
시프트 연산
[변수] << [이동할 비트 수];
[변수] >> [이동할 비트 수];
지정한 횟수대로 비트를 이동시킨다. ``<<``은 2의 거듭제곱을 곱한 효과, ``>>``은 2의 거듭제곱을 나눈 결과와 같다. 시프트 연산은 자료형의 부호 여부에 따라 동작과정이 다르다. 부호있는 자료형에 시프트 연산을 하는 경우 의도치 않은 결과가 나올 수 있으므로 항상 부호 비트를 고려해서 연산해야 한다.
- 부호 없는 자료형 : 첫째 자리나 마지막 자리를 넘어서는 비트는 사라지며, 모자라는 공간은 0으로 채운다.
- 부호 있는 자료형 : 부호 있는 자료형과 방법은 같지만 ``>>``일 경우 부호비트로 채워지고, ``<<``일 경우 0으로 채워진다. 이 과정에서 부호 비트를 덮어씌우게 되면 부호가 바뀐다.
플래그(flag)와 마스크
플래그는 적은 공간에 정보를 저장해야 하고, 빠른 속도가 필요할 때 사용한다.(ex CPU) 플래그와 마스크를 OR연산하면 플래그를 켤 수 있다. (이미 켜진 경우에는 그대로 유지) 비트를 끌때는 NOT연산을 이용하고 특정 비트가 켜져 있는지 검사할 때는 &연산자를 사용한다.
- 마스크(mask) : 플래그의 비트를 조작하거나 검사할 때 사용하는 숫자
- 토글(toggle) : 두 가지 상태만을 가지고 있는 스위치이다. 누를 때마다 값이 전환된다.
#include <stdio.h>
int main(void)
{
int i;
int result;
unsigned char flag = 0;
printf("before : %u\n", flag);
// 10진수 2진수로 변환해서 출력
result = flag;
for(i = 128; i >= 1 ; i = i / 2)
{
printf("%d", result / i);
if (i == 16)
printf(" ");
result %= i;
}
flag |= 1; // 마스크값 0000 0001과 OR연산해서 8번째 비트를 켠다.
flag |= 2; // 마스크값 0000 0010과 OR연산해서 7번째 비트를 켠다.
flag |= 4; // 마스크값 0000 0100과 OR연산해서 6번째 비트를 켠다.
printf("\n------------------\n");
printf("6 ~ 8번째 켠 후: %u\n", flag); // 0000 0111이므로 7
// 10진수 2진수로 변환해서 출력
result = flag;
for(i = 128; i >= 1 ; i = i / 2)
{
printf("%d", result / i);
if (i == 16)
printf(" ");
result %= i;
}
flag &= ~2; // 마스크값 2의 비트를 뒤집은뒤(1111 1101) AND연산해서 7번째 비트를 끈다.
printf("\n------------------\n");
printf("7번째 끈 후 : %u\n", flag); // 0000 0101이므로 5
// 10진수 2진수로 변환해서 출력
result = flag;
for(i = 128; i >= 1 ; i = i / 2)
{
printf("%d", result / i);
if (i == 16)
printf(" ");
result %= i;
}
flag ^= 1; // 마스크값 0000 0001과 XOR 연산해서 8번째 비트 토글
flag ^= 8; // 마스크값 0000 1000과 XOR 연산해서 5번째 비트 토글
printf("\n------------------\n");
printf("5, 8번째 토글 후 : %u\n", flag); // 0000 1100이므로 12
// 10진수 2진수로 변환해서 출력
result = flag;
for(i = 128; i >= 1 ; i = i / 2)
{
printf("%d", result / i);
if (i == 16)
printf(" ");
result %= i;
}
return 0;
}
플래그를 사용하는 예시이다.
``플래그 |= 마스크`` 해서 플래그를 켜고, ``플래그 &= ~마스크``해서 플래그를 끈다. (토글은 ``플래그 ^= 마스크``)
``플래그 &= 마스크``해서 플래그가 켜져있는지 검사한다.
XOR 연산의 특성과 사용예시
a ^ b = c
c ^ b = a
c ^ a = b
XOR은 위와 같은 특성을 가진다.
- 간단한 암호화
평문과 암호키를 비트 XOR연산하면 암호화된 값이 나온다. 암호화된 값과 암호키를 다시 XOR연산하면 값이 복호화되어 평문이된다. - 임시 변수 없이 두 변수의 값을 바꾸기
임시 변수없이 XOR 연산자를 세 번 사용해서 두 변수의 값을 바꿀 수있다.
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
printf("a : %d, b : %d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a : %d, b : %d\n", a, b);
return 0;
}
XOR 연산자로 두 변수의 값을 바꾸는 예시이다.
'기타 > C' 카테고리의 다른 글
[C] 파일의 분할, 헤더파일 (0) | 2020.06.17 |
---|---|
[C] 매크로와 선행 처리기(Preprocessor) (0) | 2020.06.16 |
[C] 메모리 구조와 동적할당 (0) | 2020.06.15 |
[C] 공용체(Union Type), 열거형(Enumerated Type) (0) | 2020.06.08 |
[C] 구조체 (0) | 2020.06.01 |