본문 바로가기

프로그래밍/iOS,macOS

[swift] swift에서 c함수호출시 void* 전달

 

swift만 사용하다가 요새 c 라이브러리를 좀 붙여볼 일들이 있었는데, 예전에 알던 내용이 머리속에서 리셋되어 가물가물한 상태.

연동할 c 함수의 인자가 포인터 타입일때 swift에서 어떻게 전달해야 하는지 다시한번 살펴본다.

 

 

호환 타입

Int32 int 32비트 정수
UInt32 unsigned int 부호없는 32비트 정수
Int64 long long 64비트 정수
UInt64 unsigned long long 부호없는 64비트 정수
Int long 플랫폼에 따라 32/64
UInt unsigned long 플랫폼에 따라 부호없는 32/64
Float float 32비트 부동소수점
Double double 64비트 부동소수점
Bool bool  
UnsafePointer<T> T* 포인터
UnsafeMutablePointer<T> T* 변경 가능한 포인터
UnsafeRawPointer void* 타입없는 포인터
UnsafeMutableRawPointer void* 변경 가능한 타입없는 포인터
OpaquePointer void* 구현부를 알수 없는 포인터
String const char* 문자열
StaticString const char* 컴파일 시점 문자열
@convention(c) 함수형 c 함수 포인터 swift 함수 포인터

 

 

포인터 전달

swift와 타입이 동일한 c 포인터로 전달하는 경우 inout 연산자인 & 를 사용해 값을 전달하면 된다.

이경우 mutable 형태로 전달되기때문에 var 선언된 변수만 동작한다.

// c
void c_function(int* ptr);

// swift
var value: Int = 1
c_function(&value)

 

 

포인터형으로 직접 변환해 전달하는 경우

UnsafePointer<T> -> T*

var value: Int = 1
withUnsafePointer(to: &value) { ptr in
  c_function(ptr)
}

 

 

 

void*

void* 는 swift에서 RawPointer 형으로 변경해 전달한다

이때 바로 RawPointer를 생성하지 않고, 일반 포인터로 변경하는 스코프 내에서 별도 포인터 생성 후 전달한다.

렇게 감싸지 않으면 swift 에서 포인터가 유효하지 않은 메모리를 참조할 수 있다는 경고가 발생한다.

UnsafePointer<T> -> UnsafeRawPointer -> void*

var value: Int = 1
withUnsafePointer(to: &value) { ptr in
  let rawPtr = UnsafeRawPointer(ptr)
  c_function(rawPtr)
}

 

 

 

 

 

void**

포인터의 포인터이므로, 포인터를 다시 포인터로 감싸야 하는데, void* 를 타입으로하는 포인터(UnsafePointer)를 만들어 준다.

UnsafePointer<T> -> UnsafePointer<UnsafeRawPointer> -> void**

var value: Int = 1
withUnsafePointer(to: &value) { ptr in
  let rawPtr = UnsafeRawPointer(ptr)
  withUnsafePointer(to: rawPtr) { voidPtr in
    c_function(voidPtr)
  }
}

 

 

const void**

보통 void** 만으론 사용하지 않고, 이중 포인터를 보호하기위해 const void** 를 사용한다.

이경우 void** 에서 void* 부분을 옵셔널 포인터로 다시 바인딩 해줘야 한다.

UnsafePointer<T> -> UnsafePointer<UnsafeRawPointer> -> UnsafePointer<UnsafeRawPointer?> -> const void**

var value: Int = 1
withUnsafePointer(to: &value) { ptr in
  let rawPtr = UnsafeRawPointer(ptr)
  withUnsafePointer(to: rawPtr) { voidPtrPtr in
    voidPtrPtr.withMemoryRebound(to: UnsafeRawPointer?.self, capacity: 1) { constPtrPtr in
      c_function(constVoidPtrPtr)
    }
  }
}