椿の日記

たぶんプログラムの話をします

ポインタで値を受け取る関数のFFI

C言語は、言語の都合上、関数へ渡したアドレスを用いて戻り値を受け取ることがしばしばあります。

extern "C" void ReceivePointer( int* p )
{
	*p = 100;
}

これをHaskellで受け取るために、次のような手順をとります。

  1. allocaでスタック上にメモリを割り当てる
  2. Cの関数へポインタを渡して値を受け取る
  3. ポインタ先の値をpeek関数で取得
  4. (alloca関数が終わるのでメモリが開放される)

型が理解しやすくなるように関数を分割して記述するとこんな感じ。

{-# LANGUAGE ForeignFunctionInterface #-}

import Foreign.Storable
import Foreign.Marshal
import Foreign.Ptr

foreign import ccall "ReceivePointer" c_ReceivePointer :: Ptr Int -> IO ()

receiveAction :: Ptr Int -> IO Int
receiveAction px = c_ReceivePointer px >> peek px

receive :: IO Int
receive = alloca receiveAction

main :: IO ()
main = receive >>= print