10 Stimmen

Haskell FFI: Aufruf von FunPtrs

Das ist meine Situation:

Ich würde gerne ffmpeg's av_free_packet función:

// avformat.h
static inline void av_free_packet(AVPacket *pkt)
{
  if (pkt && pkt->destruct)
    pkt->destruct(pkt);
}

Aber leider ist diese Funktion static inline und erscheint daher nicht wirklich in der verlinkten Bibliothek.

Es handelt sich jedoch um eine sehr einfache Funktion, die ich in Haskell neu implementieren könnte. Und das ist es, was ich nicht herausfinden kann, wie man es macht. Hier ist ein teilweiser Versuch (.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 = ?

Für jetzt könnte ich auf die Implementierung dieser Funktion in C (durch einfaches Aufrufen des Originals) zurückgreifen, aber es scheint mir, dass der Aufruf von Funktionszeigern irgendwie möglich sein sollte

8voto

ephemient Punkte 189038

Desde Das Haskell 98 Foreign Function Interface 1.0 ,

Dynamischer Import.

Der Typ eines dynamisch muss die folgende Form haben (FunPtr ft) -> ft , donde ft kann ein beliebiger ausländischer Typ sein.

Ein Beispiel dafür ist

foreign import ccall "dynamic"  
  mkFun :: FunPtr (CInt -> IO ()) -> (CInt -> IO ())

Die Stummelfabrik mkFun wandelt jeden Zeiger auf eine C-Funktion, die einen Integer-Wert als einziges Argument erhält und keinen Rückgabewert hat, in eine entsprechende Haskell-Funktion um.

In Ihrem Fall würde die Verwendung etwa wie folgt aussehen.

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

7voto

yairchu Punkte 21749

Ein kleines Beispiel, um zu zeigen, dass dies (die Antwort von ephemient) tatsächlich funktioniert (im Anschluss an gbacons Anliegen):

C:

#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;
}

Haskell:

{-# 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

Das funktioniert bei mir - Ausdrucke 3 % 5

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X