← 문제로

51. 비트필드(bit-field)의 레이아웃과 부호

난이도 중
내 리뷰 · C++
해설 · C++

해설 — 비트필드(bit-field)의 레이아웃과 부호

난이도: 중상

요약

비트필드는 여러 필드를 하나의 기반 정수 타입 안에 비트 단위로 채워 넣는다. 크기와 배치는 기반 타입·패킹·정렬로 정해지고, 상당 부분이 구현 정의다. 특히 폭 1의 signed 비트필드는 -1 과 0 만 표현할 수 있어 s1 = 1 이 -1 로 읽히는 함정이 있다.

실행 결과(예측; g++ x86-64 기준)

sizeof(A)=1
sizeof(B)=2
sizeof(C)=4
a: 1 5 15
b: 9 4000
c.s1=-1 c.s4=7
c.s4(-8)=-8

핵심 개념 / 단계별

  • sizeof(A)=1: A 는 1+3+4 = 8비트를 uint8_t(1바이트) 하나에 담는다. 세 필드가 한 바이트에 정확히 들어가 크기는 1.
  • sizeof(B)=2: type(4) + len(12) = 16비트 = uint16_t 하나. 크기 2, 정렬 2.
  • sizeof(C)=4: 기반 타입이 int(4바이트)다. s1+s4 는 5비트뿐이지만, 비트필드 객체의 크기·정렬은 기반 타입을 따르므로 struct 크기는 최소 sizeof(int)=4.
  • a: 1 5 15: 각 필드 폭에 값이 들어맞는다(1<2, 5<8, 15<16). +a.x 는 uint8_t 를 정수로 승격해 문자가 아닌 숫자로 출력하기 위한 단항 +.
  • b: 9 4000: type=9(4비트, <16), len=4000(12비트, <4096) 모두 표현 가능.
  • c.s1=-1: 폭 1의 signed 비트필드는 부호 비트 1개뿐 → 표현 가능한 값은 {0, -1} 뿐이다. s1=1 은 그 범위 밖이라 비트 패턴 1 이 부호 비트로 해석되어 -1.
  • c.s4=7 / c.s4=-8: 폭 4의 signed 는 2의 보수로 -8..7. 7 과 -8 모두 표현 가능해 그대로 나온다.

흔한 오해·함정

  • 부호 지정 누락: int a:1; 같이 폭 1 signed 를 "0/1 플래그"로 쓰면 값이 -1 로 나온다. 플래그엔 unsigned(또는 uint8_t) 비트필드를 써야 한다. (그냥 int : n 의 부호성 자체도 일부 맥락에서 구현 정의였던 역사가 있어 명시적 signed/unsigned 권장.)
  • 비이식성(구현 정의):
    • 필드가 기반 타입 내에서 어느 끝(LSB/MSB)부터 채워지는지(비트 순서),
    • 필드가 저장 단위 경계를 넘을 때의 패킹/패딩,
    • int 비트필드의 기본 부호성,
    • 서로 다른 컴파일러/ABI/엔디안 간 배치. → 그래서 비트필드를 그대로 네트워크/파일 포맷에 쓰면 안 된다. 이식 가능한 와이어 포맷은 명시적 시프트·마스크로 직렬화한다.
  • 오버플로 대입: 필드 폭을 넘는 값 대입은 unsigned 는 하위 비트만, signed 는 구현 정의. 범위 검증을 코드가 책임져야 한다.

면접 포인트

  • 비트필드 크기·정렬은 기반 타입이 지배한다(비트 합이 작아도 sizeof 는 기반 타입 배수).
  • 폭 1 signed 비트필드 = {0,-1} — 플래그엔 unsigned.
  • 비트필드 배치는 구현 정의라 와이어 포맷엔 부적합; 직렬화는 시프트/마스크로.