@bitCast — 타입은 바꾸되 비트 표현은 그대로

@bitCast — 타입은 바꾸되 비트 표현은 그대로

한 값의 타입만 다른 타입으로 바꾸고 싶다면? 포인터가 아니라 메모리 상의 비트 배열 그 자체를 다른 타입으로 해석하고 싶을 때 @bitCast를 써요. 값의 비트 표현(bit representation)은 그대로 두고, 그 비트를 읽는 "안경"만 다른 타입으로 바꾸는 셈이에요.

출처: Zig Documentation

본문

@bitCast는 어떤 타입의 값을 다른 타입으로 변환해요. 반환 타입은 추론된 결과 타입(inferred result type)이에요. 즉 "어디로 바꿀지"는 호출 문맥에서 결정된다는 뜻이에요.

@bitCast(value: anytype) anytype

이 변환은 두 가지를 컴파일 타임에 단언(assert) 해요.

  • @sizeOf(@TypeOf(value)) == @sizeOf(DestType) — 원본 값의 크기와 목적 타입의 크기가 같아야 해요. 비트 수가 같아야 비트를 그대로 재해석할 수 있으니까요.
  • @typeInfo(DestType) != .pointer — 목적 타입이 포인터면 안 돼요. 포인터로 메모리를 재해석해야 한다면 @ptrCast@ptrFromInt를 써야 해요.

예를 들어 이런 작업에 쓸 수 있어요.

  • f32u32의 비트로 변환하기
  • i32u32로 변환하되 2의 보수(twos complement) 비트를 그대로 보존하기

value가 컴파일 시점에 알려져 있으면 @bitCast는 컴파일 타임에도 동작해요.

한 가지 꼭 짚어둘 게 있어요. 메모리 레이아웃이 정의되지 않은(undefined layout) 값을 bitcast 하는 건 컴파일 오류예요. 어떤 타입들이 안 되느냐 하면요.

  • 전용 캐스팅 빌트인이 따로 있는 타입 (포인터, 에러 셋)
  • 빈 구조체(bare struct), 에러 유니온(error union), 슬라이스, 옵셔널(optional)
  • 그 외에도 메모리 레이아웃이 명확히 정의되지 않은 모든 타입

이런 타입들은 "비트가 어떤 식으로 배치돼 있는지"가 보장되지 않으니, 비트를 그대로 들고 가는 @bitCast에 쓰이는 게 처음부터 차단돼 있어요.

또 하나, 대응하는 태그 값(tag value)이 없는 정수를 enum으로 바꾸려는 시도는 안전 검사가 걸린 Illegal Behavior(safety-checked Illegal Behavior)를 불러일으켜요.

더 알아보기 (Learn more)

연관된 캐스팅 빌트인들을 함께 봐두면 상황별로 뭘 써야 할지 분명해져요.