본문 바로가기
카테고리 없음

C언어 - 비트 연산자 총정리

by kik328288 2026. 5. 5.

C언어 비트 연산자 총정리, 실기 예제 포함

C언어가 시스템 프로그래밍의 표준 언어로 오랜 시간 자리를 지켜온 핵심 이유 중 하나는 메모리의 비트(Bit) 수준까지 직접 다룰 수 있다는 점이다. 운영체제 커널, 임베디드 펌웨어, 네트워크 프로토콜 구현 같은 영역에서는 한 바이트의 어떤 비트가 1인지 0인지를 정확히 제어하는 능력이 곧 성능과 효율을 결정한다. 이를 가능하게 하는 도구가 비트 연산자(Bitwise Operator)이며, AND·OR·XOR·NOT의 네 가지 논리 연산자와 좌·우 시프트의 두 가지 이동 연산자로 구성된다. 정보처리기사 실기에서도 비트 연산의 결과를 2진수와 10진수로 추적하는 문제가 자주 출제된다. 본 글은 여섯 가지 비트 연산자의 의미와 활용 패턴, 그리고 시험 빈출 예제를 코드와 함께 정리한다.

 

비트 논리 연산자 — AND, OR, XOR, NOT

비트 논리 연산자는 두 정수의 같은 위치 비트끼리 논리 연산을 수행한다. 일반적인 논리 연산자(&&, ||, !)가 식 전체를 참 또는 거짓으로 평가하는 반면, 비트 연산자는 각 자리 비트마다 독립적으로 동작한다는 점이 결정적인 차이이다. 이 차이를 정확히 이해하는 것이 비트 연산 학습의 출발점이다.

비트 AND 연산자(&)는 두 비트가 모두 1일 때만 결과가 1이 되고, 그 외에는 0이 된다. 따라서 특정 비트를 추출하거나 마스킹할 때 가장 자주 사용된다. 비트 OR 연산자(|)는 두 비트 중 하나라도 1이면 결과가 1이며, 특정 비트를 1로 설정할 때 활용된다. 비트 XOR 연산자(^)는 두 비트가 서로 다를 때만 1이 되며, 특정 비트를 토글하거나 두 변수의 값을 교환하는 트릭에 쓰인다. 마지막으로 비트 NOT 연산자(~)는 단항 연산자로, 모든 비트를 반전시킨다.

int a = 12;   // 0000 1100
int b = 10;   // 0000 1010

printf("%d\n", a & b);   // 0000 1000 = 8
printf("%d\n", a | b);   // 0000 1110 = 14
printf("%d\n", a ^ b);   // 0000 0110 = 6
printf("%d\n", ~a);      // 1111 0011 = -13 (2의 보수)

비트 NOT 연산자의 결과가 음수로 나오는 이유는 C언어의 정수가 2의 보수 형식으로 표현되기 때문이다. 12의 모든 비트를 뒤집으면 부호 비트까지 1이 되어 음수로 해석된다. 정보처리기사 실기에서도 이 부호 처리 방식이 종종 출제되므로, 2진수와 10진수의 변환 절차를 손으로 한 번씩 따라가 보는 연습이 매우 유용하다.

비트 연산은 짝수와 홀수 판별, 플래그 검사, 권한 비트 처리 같은 실무 작업에 광범위하게 활용된다. 예를 들어 한 정수의 가장 낮은 비트를 검사하면 그 수가 짝수인지 홀수인지를 단 한 번의 AND 연산으로 알 수 있다.

int n = 7;
if (n & 1) {
    printf("홀수\n");
} else {
    printf("짝수\n");
}
// 출력: 홀수

시프트 연산과 비트 마스킹 응용

시프트 연산자는 비트들을 좌우로 이동시키는 연산이며, 두 가지 방향이 있다. 좌측 시프트(<<)는 비트들을 왼쪽으로 옮기고 오른쪽 빈자리는 0으로 채운다. 결과적으로 정수를 2의 거듭제곱만큼 곱한 값과 같다. 우측 시프트(>>)는 비트들을 오른쪽으로 옮기며, 부호 있는 정수에서는 부호 비트를 그대로 채우는 산술 시프트가 적용되어 음수의 부호가 유지된다. 두 연산은 곱셈·나눗셈보다 훨씬 빠르게 처리되므로 성능이 중요한 코드에서 자주 활용된다.

int x = 5;             // 0000 0101
printf("%d\n", x << 2); // 0001 0100 = 20  (5 * 4)
printf("%d\n", x << 3); // 0010 1000 = 40  (5 * 8)

int y = 40;             // 0010 1000
printf("%d\n", y >> 2); // 0000 1010 = 10  (40 / 4)
printf("%d\n", y >> 3); // 0000 0101 = 5   (40 / 8)

이러한 비트 연산자들을 결합하면 비트 마스킹(Bit Masking)이라는 강력한 기법을 만들 수 있다. 마스크는 특정 위치의 비트만 1로 설정해 놓은 정수이며, AND·OR·XOR과 결합해 원하는 비트만 추출하거나, 설정하거나, 토글할 수 있다. 가장 자주 사용되는 세 가지 패턴은 다음과 같다.

unsigned char flags = 0b00000000;

// 1. 특정 비트 설정 (3번 비트를 1로)
flags |= (1 << 3);   // 0000 1000
printf("%d\n", flags);  // 8

// 2. 특정 비트 해제 (3번 비트를 0으로)
flags &= ~(1 << 3);  // 0000 0000
printf("%d\n", flags);  // 0

// 3. 특정 비트 토글 (5번 비트 반전)
flags ^= (1 << 5);   // 0010 0000
printf("%d\n", flags);  // 32

이 세 패턴은 권한 관리, 파일 모드 비트, 그래픽스의 색상 채널 추출 등 다양한 실무 영역에서 표준적으로 사용된다. 예를 들어 리눅스 파일 권한의 읽기·쓰기·실행 비트를 다루거나, RGB 색상의 빨간 채널을 분리하거나, 하드웨어 제어 레지스터의 특정 비트만 조작하는 모든 작업이 동일한 원리로 동작한다. 비트 마스킹을 자유롭게 다룰 수 있는 능력은 시스템 프로그래밍의 기초 체력이라 해도 과언이 아니다.

정보처리기사 실기 빈출 비트 연산 예제

정보처리기사 실기에서 비트 연산은 단순 출력 문제로 가장 많이 등장한다. 2진수 변환과 연산을 정확히 손으로 추적할 수 있다면 어떤 변형 문제든 안정적으로 풀 수 있다. 다음 네 가지 패턴이 핵심이다.

유형 1: 기본 비트 연산의 결과 추적.

int a = 13;   // 0000 1101
int b = 9;    // 0000 1001

printf("%d\n", a & b);  // 0000 1001 = 9
printf("%d\n", a | b);  // 0000 1101 = 13
printf("%d\n", a ^ b);  // 0000 0100 = 4

가장 기본적인 패턴이지만 출제 빈도가 가장 높다. 두 수를 2진수로 변환한 뒤 자릿수별로 연산하는 절차를 빠르게 수행할 수 있어야 한다.

유형 2: 시프트 연산과 곱셈·나눗셈의 등가성.

int x = 6;
printf("%d\n", x << 2);  // 6 * 4 = 24
printf("%d\n", x >> 1);  // 6 / 2 = 3

int y = 17;
printf("%d\n", y >> 2);  // 17 / 4 = 4 (소수점 버림)

좌측 시프트는 곱셈, 우측 시프트는 나눗셈과 같다는 등가성을 묻는다. 우측 시프트 결과에서 소수점 이하가 버려진다는 점이 자주 출제된다.

유형 3: 비트 마스킹과 플래그 검사.

int flags = 0b1010;       // 10진수 10

// 0번 비트가 켜져 있는지 검사
if (flags & (1 << 0))
    printf("bit0 ON\n");
else
    printf("bit0 OFF\n");

// 1번 비트가 켜져 있는지 검사
if (flags & (1 << 1))
    printf("bit1 ON\n");
else
    printf("bit1 OFF\n");

// 출력:
// bit0 OFF
// bit1 ON

특정 비트가 1인지 0인지 검사하는 표준 패턴이다. (1 << n)이 만들어내는 마스크의 형태를 정확히 떠올릴 수 있어야 한다.

유형 4: XOR을 활용한 값 교환.

int a = 5, b = 3;
a = a ^ b;   // a = 0110
b = a ^ b;   // b = 0101 = 5
a = a ^ b;   // a = 0011 = 3
printf("%d %d\n", a, b);  // 3 5

임시 변수 없이 두 변수를 교환하는 XOR 트릭이다. 자주 쓰는 코드는 아니지만 시험에서는 단골 손님이며, XOR이 같은 값으로 두 번 적용되면 원래 값이 된다는 성질이 핵심 원리이다.

이 네 가지 패턴을 손으로 추적하는 연습만으로 비트 연산 영역의 시험 대비는 충분하다. 비트 연산은 결국 한 자리 비트씩 독립적으로 처리한다는 단순한 규칙으로 요약된다. 그 단순함 위에 마스킹과 시프트가 더해지면 시스템 프로그래밍의 토대가 완성되며, 이 능력은 자료구조의 비트셋, 운영체제의 권한 관리, 네트워크의 패킷 헤더 해석 같은 후속 학습으로 자연스럽게 이어진다. 본 글로 #26 변수와 데이터 타입에서 시작한 C언어 10편 시리즈가 마무리된다. 변수·제어문·함수·포인터·배열·구조체·동적 메모리·파일 입출력·전처리기·비트 연산이라는 열 가지 토대를 갖춘 독자라면, 이제 자료구조와 운영체제로 학습 영역을 확장할 준비가 충분히 갖추어졌다고 할 수 있다.


메타 디스크립션: C언어 비트 연산자 &·|·^·~·<<·>>의 의미와 동작, 비트 마스킹을 활용한 플래그 설정·해제·토글 패턴, 그리고 정보처리기사 실기 빈출 4패턴을 코드 예시와 함께 정리합니다. C언어 10편 시리즈 마무리 글입니다.


소개 및 문의 · 개인정보처리방침 · 면책조항

© 2026 블로그 이름