C 바인딩: union

C 바인딩: union

C 구조체와 마찬가지로, C의 union을 Crystal에서 쓰고 싶을 때가 있어요. lib 선언 안에서 union을 쓰면 C union을 그대로 선언할 수 있어요.

출처: Crystal 공식 문서

본문

lib 안의 union 선언은 C union을 선언해요.

lib U
  # In C:
  #
  #  union IntOrFloat {
  #    int some_int;
  #    double some_float;
  #  };
  union IntOrFloat
    some_int : Int32
    some_float : Float64
  end
end

union의 인스턴스를 만들려면 new를 써요.

value = U::IntOrFloat.new

이렇게 하면 union이 스택에 할당돼요.

C union은 모든 필드가 "0"으로 시작해요. 정수와 실수는 0에서 시작하고, 포인터는 주소 0을 가리키는 식이죠.

이 초기화를 피하고 싶다면 uninitialized를 쓸 수 있어요.

value = uninitialized U::IntOrFloat
value.some_int # => some garbage value

프로퍼티를 설정하고 읽을 수 있어요.

value = U::IntOrFloat.new
value.some_int = 1
value.some_int   # => 1
value.some_float # => 4.94066e-324

할당한 값이 프로퍼티의 타입과 정확히 같지 않으면 to_unsafe가 시도돼요.

C union은 함수와 메서드에 값(복사본)으로 전달되고, 메서드에서 반환할 때도 값으로 전달돼요.

def change_it(value)
  value.some_int = 1
end

value = U::IntOrFloat.new
change_it value
value.some_int # => 0

union 필드 타입에 쓰이는 표기법은 타입 문법을 참고하세요.

더 알아보기

  • C union은 값으로 전달되므로, 함수 안에서 바꿔도 원래 값은 바뀌지 않아요. 위 예시에서 some_int가 여전히 0인 이유죠.
  • C 바인딩의 다른 개념은 C 바인딩 문서에서 확인할 수 있어요.