프로그래밍임베디드 C 엔지니어

C 언어에서 비트 연산자 (&, |, ^, ~, <<, >>)는 어떻게 작동합니까? 다양한 길이와 부호의 타입에 대한 작업 시 이들의 특성은 무엇이며, 개발자들이 그 사용 시 자주 저지르는 오류는 무엇입니까?

Hintsage AI 어시스턴트로 면접 통과

답변.

비트 연산자는 정수형의 개별 비트를 조작합니다:

  • & — 비트 AND
  • | — 비트 OR
  • ^ — 비트 배타적 OR
  • ~ — 비트 NOT
  • << — 왼쪽 시프트
  • >> — 오른쪽 시프트

특징:

  • 연산자는 정수형 타입(int, unsigned int, 등)에서만 작동합니다.
  • 부호가 있는 숫자(signed)의 경우 오른쪽 시프트(>>)시 산술 시프트 또는 논리 시프트가 발생할 수 있으며, 이는 컴파일러에 따라 다릅니다.
  • 비트 수가 변수의 비트 수를 초과하는 시프트는 정의되지 않은 동작을 일으킵니다.
  • 신뢰성 있는 작업을 위해 unsigned 타입을 선택하여 부호 확장을 피하는 것이 좋습니다.

예:

unsigned int flags = 0; flags |= 0x1; // 0 번째 비트 설정 flags &= ~0x2; // 1 번째 비트 리셋 if ((flags & 0x4) != 0) { /* ... */ } // 2 번째 비트 확인

함정 질문.

signed intunsigned int의 오른쪽 시프트(>>)의 차이는 무엇인가요?

자주 잘못된 답변: 오른쪽 시프트는 항상 왼쪽에 0을 삽입한다고 여깁니다, 부호에 관계없이.

올바른 답변: unsigned int의 경우 오른쪽 시프트(>>)는 항상 0을 삽입합니다. signed int의 경우 삽입되는 것은 부호(음수가 될 경우 1) 또는 0이며, 이는 컴파일러의 구현(아키텍처 및 C 표준의 규칙)에 따라 달라집니다.

예:

signed int a = -8; unsigned int b = (unsigned int)a; printf("%d ", a >> 1); printf("%u ", b >> 1);

첫 번째 경우 결과는 컴파일러에 따라 다르며, 두 번째 경우는 항상 0으로의 논리적 시프트가 됩니다.

주제의 미세한 차이에 대한 잘못된 사용 사례.


이야기

프로토콜 처리 코드에서 신호 플래그가 char 타입에 저장되었습니다. 프로그래머는 8비트 시프트(flag << 8)를 적용했으며, 이는 오버플로와 타입 승격 규칙으로 인해 모든 데이터가 손실되어 결과가 항상 0이 되었습니다.


이야기

네트워크 프로토콜에서 데이터 읽기 (big-endian). 바이트를 결합하기 위해 비트 연산을 사용할 때 unsigned로 변환하지 않아 구조체의 필드를 읽을 때 가끔 예기치 않은 음수 값이 발생했습니다.


이야기

~ (비트 NOT)를 사용하여 int 타입의 비트를 리셋할 때 (예: ~0x80), 이는 0x7F로 해석되지만 실제로는 음수 -129가 되어 후속 계산 및 논리적 검증 시 오류를 발생시켰습니다.