Вопрос
Вот моя ситуация:
Я хотел бы позвонить в ffmpeg av_free_packet
функция:
// avformat.h
static inline void av_free_packet(AVPacket *pkt)
{
if (pkt && pkt->destruct)
pkt->destruct(pkt);
}
Но, к сожалению, эта функция static inline
, и поэтому на самом деле не отображается в связанной библиотеке.
Однако это очень простая функция, которую я мог бы переопределить в Haskell.И вот я не могу понять, как это сделать.Вот частичная попытка (.hsc):
av_free_packet :: Ptr AVPacket -> IO ()
av_free_packet pkt =
when (nullPtr /= pkt) $ do
destruct <- (#peek AVPacket, destruct) pkt :: IO (FunPtr (Ptr AVPacket -> IO ()))
when (nullFunPtr /= destruct) $ funPtrToFun destruct pkt
funPtrToFun :: FunPtr a -> a
funPtrToFun = ?
Сейчас я мог бы прибегнуть к реализации этой функции на C (просто вызвав оригинал), но мне кажется, что вызов указателей функций должен быть каким-то образом возможен.
Решение
От Интерфейс внешних функций Haskell 98 1.0,
Динамический импорт.
Тип динамичный заглушка должна иметь вид
(FunPtr ft) -> ft
, гдеft
может быть любого иностранного типа.В качестве примера рассмотрим
foreign import ccall "dynamic" mkFun :: FunPtr (CInt -> IO ()) -> (CInt -> IO ())
Фабрика заглушек
mkFun
преобразует любой указатель на функцию C, которая получает целочисленное значение в качестве единственного аргумента и не имеет возвращаемого значения, в соответствующую функцию Haskell.
В вашем случае использование будет выглядеть примерно так.
foreign import ccall "dynamic"
funPktToNil:: FunPtr (Ptr AVPacket -> IO ()) -> Ptr AVPacket -> IO ()
av_free_packet :: Ptr AVPacket -> IO ()
av_free_packet pkt =
when (nullPtr /= pkt) $ do
destruct <- (#peek AVPacket, destruct) pkt
when (nullFunPtr /= destruct) $ funPktToNil destruct pkt
Другие советы
Небольшой пример, демонстрирующий, что это (ответ эфемиента) действительно работает (в соответствии с беспокойством gbacon):
С:
#include <stdio.h>
typedef void funcType(int, int);
typedef funcType * pFuncType;
void printer(int a, int b) {
printf("%d %% %d\n", a, b);
}
pFuncType gimmeFunc(int dummy) {
return printer;
}
Хаскелл:
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.Ptr
foreign import ccall unsafe "gimmeFunc"
c_gimmeFunc :: Int -> IO (FunPtr (Int -> Int -> IO ()))
foreign import ccall "dynamic"
mkFunIntIntNil :: FunPtr (Int -> Int -> IO ()) -> Int -> Int -> IO ()
main :: IO ()
main = do
fun <- c_gimmeFunc 1
mkFunIntIntNil fun 3 5
Это работает для меня - печатает 3 % 5