Coding/C

[C언어] 비트 연산자 - 코딩도장

GunP4ng 2023. 12. 13. 23:12

[코딩도장] Unit 23 ~ 25


1. 비트 연산자 사용하기

1. 비트 연산자

비트 연산자는 바이트 단위보다 더 작은 비트 단위로 연산하는 연산자이다

비트 연산자 종류

비트 연산은 모든 연산을 2진수로 계산한다

비트로 옵션을 설정할 때 주로 사용하며 저장공간을 아낄 수 있다는 장점이 있다

이런 방식을 플래그( flag )라고 한다

 

& 연산자

& 연산자는 비트 AND 이므로 두 비트가 모두 1일 때 1이 된다

1 1 → 1

0 1 → 0

0 1 → 0

0 0 → 0

 

| 연산자

| 연산자는 비트 OR 이므로 둘 중 하나의 비트가 1일 때 1이 된다

1 1 → 1

0 1 → 1

1 0 → 1

0 0 → 0

 

^ 연산자

^ 연산자는 비트 XOR 이므로 두 비트가 다를 때 1이다

1 1 → 0

0 1 → 1

1 0 → 1

0 0 → 0

 

~ 연산자

~ 연산자는 비트 NOT 연산자이다

0은 1로 1은 0으로 바꾸며 "비트를 뒤집는다" 또는 "비트 반전"이라고 말한다

0 → 1

1 → 0

 

<<, >>  시프트 연산자

지정한 횟수대로 비트를 이동시키고 모자란 부분은 0으로 채운다

변수 << 이동할 비트 수

변수 >> 이동할 비트 수

형식으로 사용한다

시프트 연산

 

 

2. 비트 연산자로 플래그 처리하기

플래그는 적은 공간에 정보를 저장해야 하고

빠른 속도가 필요할 때 사용한다

CPU는 내부 저장 공간이 작기 때문에 대부분의 정보를 비트로 저장한다

리눅스 커널의 소스 코드나 하드웨어에서 사용한다

 

4Byte = 32Bit, 32개의 상태 처리 가능

0100 0001    // 두 번째 비트와 여덟 번째 비트가 켜진 상태(on)

 

마스크(mask)는 비트의 플래그를 조작하거나 검사할 때 사용하는 숫자를 말한다

 

특정 비트를 키는 법

flag |= 마스크

OR연산의 특성을 이용한다

0 | 1 → 1    꺼짐 → 켜짐

1 | 1 → 1    켜짐 → 켜짐

 

특정 비트를 끄는 법

flag &= ~마스크

마스크 값을 ~  연산자로 뒤집고

&= 연산을 통해 비트를 끈다

unsigned char flag = 7;		// 7: 0000 0111

flag &= ~2;

 

마스크 값인 2의 비트를 뒤집으면

0000 0010
_________ ~
1111 1101

 

플래그와 마스크를 AND 연산하면

플래그의 비트 끄기

이렇게 원하는 비트를 끌 수 있다

 

토글(toggle) 하는 법

비트가 켜져있다면 끄고 꺼져있다면 키는 방법

XOR연산의 특성을 이용한다

두 비트가 다르면 1 같으면 0이 된다

1 ^ 1 → 0        켜짐 → 꺼짐

0 ^ 1 → 1        꺼짐 → 켜짐

1 ^ 0 → 1        켜짐 → 켜짐

0 ^ 0 → 0        꺼짐 → 꺼짐

 

flag = 7 mask = 2 를 토글하면

플래그의 비트 토글하기

0000 0101 이 된다


2. 심사문제

23.8 비트 논리 연산자 사용하기

표준 입력으로 두 정수(unsigned int)가 입력됩니다. 입력된 두 정수의 비트 연산 결과를 각 줄에 출력하는 프로그램을 만드세요(scanf 함수 호출 전에 문자열을 출력하면 안 됩니다).

  1. num1 num2을 비트 XOR 연산
  2. num1 num2을 비트 OR 연산
  3. num1 num2를 비트 AND 연산
  4. num1을 비트 NOT 연산

출력 결과는 서식 지정자 %u를 사용하세요.

정답에는 C 언어 컴파일러에서 정상적으로 컴파일되는 전체 코드를 입력해야 합니다.

#include <stdio.h>
 
int main() {
    unsigned int num1, num2;
    scanf("%u %u", &num1, &num2);

    printf("%u\n", num1 ^ num2);
    printf("%u\n", num1 | num2);
    printf("%u\n", num1 & num2);
    printf("%u\n", ~ num1);

    return 0;
}

23.9 시프트 연산자 사용하기

표준 입력으로 정수가 입력됩니다. 입력된 정수를 왼쪽으로 20번, 오른쪽으로 4번 시프트 연산하여 결과를 출력하는 프로그램을 만드세요(scanf 함수 호출 전에 문자열을 출력하면 안 됩니다). 단, 정수형 변수는 unsigned long long으로 선언하고 출력 결과는 서식 지정자 %llu를 사용하세요.

정답에는 C 언어 컴파일러에서 정상적으로 컴파일되는 전체 코드를 입력해야 합니다.

#include <stdio.h>
 
int main() {
    unsigned long long int num1;
    scanf("%llu", &num1);

    num1 <<= 20;
    num1 >>= 4;
    printf("%llu", num1);

    return 0;
}

24.7 시프트 연산과 플래그 활용하기

표준 입력으로 두 정수가 입력됩니다(입력 값의 범위는 0~255). 플래그에 다음과 같은 연산을 하여 결과가 출력되게 만드세요. 정답에는 밑줄 친 부분에 들어갈 코드만 작성해야 합니다.

  1. num1의 비트를 왼쪽으로 3번 이동한 값으로 flag의 비트 켜기
  2. num2의 비트를 오른쪽으로 2번 이동한 값으로 flag의 비트 끄기
  3. flag의 첫 번째 비트 토글하기
#define __USE_MINGW_ANSI_STDIO 1 // Dev-C++(MinGW)에서 %hhu를 사용하기 위한 설정
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
 
int main()
{
    unsigned char flag = 16;
    unsigned char num1, num2;
 
    scanf("%hhu %hhu", &num1, &num2);
 
    ___________________
    ___________________
    ___________________
 
    printf("%u\n", flag);
 
    return 0;
}

 

정답

flag |= (num1 <<= 3);
flag &= ~(num2 >>= 2);
flag ^= (1 << 7);

 

16 : 0001 0000

 

num1 <<= 3 의 값으로 비트 켜기

비트를 키려면 |= 연산자를 사용해야 한다

flag |= (num1 <<= 3)


num2 >>= 2 의 값으로 비트 끄기

비트를 끄려면 ~ 연산자를 이용해 마스크를 뒤집고 &= 연산자를 사용한다

flag &= ~(num2 >>= 2)

 

flag 의 첫번째 비트 토글하기

비트를 토글하기 위해서는 ^= 연산자를 사용한다

1은 8번째 비트이기 때문에 왼쪽으로 7번 이동시킨다

flag ^= (1 << 7)


25.6 괄호 사용하기

표준 입력으로 세 정수가 입력됩니다. 다음 순서대로 연산한 뒤 결과가 출력되게 만드세요.

  1. num1 num2를 더하기
  2. 1번 결과에 10을 곱하기
  3. 2번 결과에서 num3을 빼기

정답에는 밑줄 친 부분에 들어갈 코드만 작성해야 합니다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    int num1;
    int num2;
    int num3;

    scanf("%d %d %d", &num1, &num2, &num3);

    printf("%d\n", _________________________);

    return 0;
}

 

정답

((num1 + num2) * 10) - num3