Foreign.Ptr — 외부 엔티티를 가리키는 타입 포인터

Foreign.Ptr — 외부 엔티티를 가리키는 타입 포인터

Foreign.Ptr 모듈은 외부(foreign) 엔티티를 가리키는 '타입 있는' 포인터를 제공해요. FFI 코드에서는 C 메모리나 함수를 직접 다룰 때가 많은데, 이런 값을 포인터로 표현하면 타입 안전성을 누릴 수 있어요. 이 모듈은 데이터를 가리키는 Ptr과 함수를 가리키는 FunPtr을 구분해서 제공하고, 포인터 사이의 변환·연산·정수로의 무손실 변환 함수들을 함께 담고 있어요.

출처: Haskell 2010 언어 리포트

본문

이 모듈이 내보내는 것들은 다음과 같아요.

module Foreign.Ptr (

    Ptr,  nullPtr,  castPtr,  plusPtr,  alignPtr,  minusPtr,  FunPtr,

    nullFunPtr,  castFunPtr,  castFunPtrToPtr,  castPtrToFunPtr,

    freeHaskellFunPtr,  IntPtr,  ptrToIntPtr,  intPtrToPtr,  WordPtr,

    ptrToWordPtr,  wordPtrToPtr

  ) where

모듈 Foreign.Ptr은 외부 엔티티를 가리키는 타입 있는 포인터를 제공해요. 우리는 두 종류의 포인터를 구분해요: 데이터를 가리키는 포인터와 함수를 가리키는 포인터. 이 두 종류의 포인터는 각각 데이터 세그먼트와 텍스트 세그먼트를 참조할 수 있으므로 다르게 표현될 수 있다는 점을 이해해야 해요.

35.1 데이터 포인터

data Ptr a

Ptr a 타입의 값은 객체, 또는 객체 배열을 가리키고, 그 객체들은 타입 a의 Haskell 값으로(또는 그 반대로) 마샬링될 수 있어요. 타입 a는 대개 마샬링 연산을 제공하는 Foreign.Storable.Storable 클래스의 인스턴스예요. 하지만 이것이 필수적인 것은 아니며, 포인터에 접근하기 위한 나만의 연산을 직접 제공할 수도 있어요. 예를 들어 C 구조체의 필드를 읽고 쓰는 작은 외부 함수들을 직접 작성할 수 있겠죠.

instance Eq (Ptr a)  instance Ord (Ptr a)  instance Show (Ptr a)  instance Storable (Ptr a)
nullPtr :: Ptr a

상수 nullPtr은 유효한 메모리 위치와 연관되지 않은 특별한 Ptr 값을 담고 있어요.

castPtr :: Ptr a -> Ptr b

castPtr 함수는 포인터를 한 타입에서 다른 타입으로 캐스팅해요.

plusPtr :: Ptr a -> Int -> Ptr b

주어진 주소를 주어진 바이트 단위 오프셋만큼 앞으로 이동시켜요.

alignPtr :: Ptr a -> Int -> Ptr a

임의의 주소와 정렬(alignment) 제약이 주어지면, alignPtr은 그 정렬 제약을 만족하는 더 높은 다음 주소를 돌려줘요. 정렬 제약 xx로 나누어떨어지는 모든 주소에 의해 충족돼요. 이 연산은 멱등적(idempotent)이에요.

minusPtr :: Ptr a -> Ptr b -> Int

두 번째 인자에서 첫 번째 인자로 가는 데 필요한 오프셋을 계산해요. 다음이 성립해요.

 p2 == p1 ‘plusPtr‘ (p2 ‘minusPtr‘ p1)

35.2 함수 포인터

data FunPtr a

FunPtr a 타입의 값은 외부 코드에서 호출할 수 있는 함수를 가리키는 포인터예요. 타입 a는 보통 외부 타입, 즉 인자를 0개 이상 갖는 함수 타입인데, 각 인자 타입은 마샬링 가능한 외부 타입이어야 해요. 즉 Char, Int, Double, Float, Bool, Data.Int.Int8, Data.Int.Int16, Data.Int.Int32, Data.Int.Int64, Data.Word.Word8, Data.Word.Word16, Data.Word.Word32, Data.Word.Word64, Ptr a, FunPtr a, Foreign.StablePtr.StablePtr a, 또는 이들을 newtype으로 이름 바꾼 것이어야 해요. 반환 타입은 마샬링 가능한 외부 타입이거나, IO t의 형태(여기서 t는 마샬링 가능한 외부 타입 또는 ())여야 해요. FunPtr a 타입의 값은 외부 함수를 가리키는 포인터일 수 있는데, 다른 외부 함수가 돌려준 것이거나 다음과 같은 정적 주소 import로 불러온 것일 수 있어요.

 foreign import ccall "stdlib.h "

   p_free :: FunPtr (Ptr a -> IO ())

또는 올바른 타입의 FunPtr을 만들어 내도록 선언된 wrapper 스텁을 사용해 만들어진 Haskell 함수를 가리키는 포인터일 수 있어요. 예를 들어:

 type Compare = Int -> Int -> Bool

 foreign import ccall "wrapper"

   mkCompare :: Compare -> IO (FunPtr Compare)

mkCompare 같은 wrapper 스텁에 대한 호출은 저장 공간을 할당하는데, 더 이상 필요 없을 때는 Foreign.Ptr.freeHaskellFunPtr로 해제해야 해요. FunPtr 값을 대응하는 Haskell 함수로 변환하려면, 특정 외부 타입에 대한 dynamic 스텁을 정의하면 돼요. 예:

 type IntFunction = CInt -> IO ()

 foreign import ccall "dynamic"

   mkFun :: FunPtr IntFunction -> IntFunction
instance Eq (FunPtr a)  instance Ord (FunPtr a)  instance Show (FunPtr a)  instance Storable (FunPtr a)
nullFunPtr :: FunPtr a

상수 nullFunPtr은 유효한 메모리 위치와 연관되지 않은 특별한 FunPtr 값을 담고 있어요.

castFunPtr :: FunPtr a -> FunPtr b

FunPtr을 다른 타입의 FunPtr로 캐스팅해요.

castFunPtrToPtr :: FunPtr a -> Ptr b

FunPtrPtr로 캐스팅해요. 주의: 이는 데이터 포인터와 함수 포인터가 같은 주소 범위를 공유하는 아키텍처에서만 유효하며, 이미 이 가정에 의존하는 외부 라이브러리에 대한 바인딩에서만 사용해야 해요.

castPtrToFunPtr :: Ptr a -> FunPtr b

PtrFunPtr로 캐스팅해요. 주의: 이는 데이터 포인터와 함수 포인터가 같은 주소 범위를 공유하는 아키텍처에서만 유효하며, 이미 이 가정에 의존하는 외부 라이브러리에 대한 바인딩에서만 사용해야 해요.

freeHaskellFunPtr :: FunPtr a -> IO ()

주어진 FunPtr과 연관된 저장 공간을 해제하는데, 그 FunPtr은 반드시 wrapper 스텁에서 얻은 것이어야 해요. 이 함수는 foreign import wrapper 함수의 반환 값이 더 이상 필요 없을 때마다 호출해야 해요. 그렇지 않으면 그것이 사용하는 저장 공간이 누수(leak)돼요.

35.3 포인터와의 손실 없는 상호 변환이 가능한 정수 타입

data IntPtr

Ptr과 손실 없이 서로 변환될 수 있는 부호 있는 정수 타입이에요. 이 타입은 C99의 intptr_t 타입과도 호환되며, 그 타입으로 안전하게 마샬링될 수 있어요.

instance Bounded IntPtr instance Enum IntPtr instance Eq IntPtr  instance Integral IntPtr  instance Num IntPtr instance Ord IntPtr instance Read IntPtr  instance Real IntPtr  instance Show IntPtr  instance Storable IntPtr  instance Bits IntPtr
ptrToIntPtr :: Ptr a -> IntPtr

PtrIntPtr로 캐스팅해요.

intPtrToPtr :: IntPtr -> Ptr a

IntPtrPtr로 캐스팅해요.

data WordPtr

Ptr과 손실 없이 서로 변환될 수 있는 부호 없는 정수 타입이에요. 이 타입은 C99의 uintptr_t 타입과도 호환되며, 그 타입으로 안전하게 마샬링될 수 있어요.

instance Bounded WordPtr instance Enum WordPtr instance Eq WordPtr  instance Integral WordPtr  instance Num WordPtr instance Ord WordPtr instance Read WordPtr  instance Real WordPtr  instance Show WordPtr  instance Storable WordPtr  instance Bits WordPtr
ptrToWordPtr :: Ptr a -> WordPtr

PtrWordPtr로 캐스팅해요.

wordPtrToPtr :: WordPtr -> Ptr a

WordPtrPtr로 캐스팅해요.

더 알아보기 (Learn more)