2016-03-07 6 views
5

Ich versuche, die CFFI Wrapper für Sundials CVODE Bibliothek zu schreiben. SWIG wurde erstickt an Sundials Header, da sie ganz miteinander verbunden sind und SWIG könnten die richtigen Header nicht finden, so dass ich es von Hand tat ein bisschen mühsam, aber ich habe es geschafft.Common Lisp CFFI: Zeiger auf den Zeiger

Jetzt versuche ich, zu testen, ob es korrekt funktioniert. Vorerst einfach das "Problemobjekt" erstellen und löschen. Hier beginnt das Problem. So wird das "Problem-Objekt" über Funktion zugewiesen

SUNDIALS_EXPORT void *CVodeCreate(int lmm, int iter); 

für die ich den Wrapper erstellt:

(cffi:defcfun "CVodeCreate" :pointer 
    (lmm :int) 
    (iter :int)) 

PS. SUNDIALS_EXPORT (zumindest auf Unix) ist im Grunde nichts.

, nun das Objekt zu zerstören, verwendet Sundials seine eigene Funktion:

SUNDIALS_EXPORT void CVodeFree(void **cvode_mem); 

Also, ich brauche es den Verweis auf das von CVodeCreate erstellte Objekt zu übergeben. In C, wenn meine Erinnerung nicht fehlerhaft ist, hätte ich etwas wie CVodeFree(&problem_object) getan. In CL habe ich diesen Wrapper für die Funktion geschrieben:

(cffi:defcfun "CVodeFree" :void 
    (cvode-mem :pointer)) 

So, hier COVDE-MEM ist ein Zeiger auf einen Zeiger. Frage ist, wie man den Zeiger des Zeigers in CL/CFFI erhält? Hier ist der Anfang des Codes:

(defvar *p* (cvodecreate 1 2)) 

(. PS Sie nicht über die Zahlen Sorgen zu CVODECREATE weitergegeben, sie sagen nur, welche Methoden zu verwenden, um noch zu definierten Konstanten müssen, um es besser lesbar)

So *P* ist so etwas wie

#.(SB-SYS:INT-SAP #X7FFFE0007060) 

Wenn ich es direkt an CVODEFREE passieren, es endet in Fehler auf:

CL-USER> (cvodefree *p*) 
; Evaluation aborted on #<SIMPLE-ERROR "bus error at #X~X" {1005EC9BD3}>. 

Ich habe versucht, (CFFI:POINTER-ADDRESS *P*) vorbei, aber es führt zu ähnlich „Bus-Fehler ...“ (nicht einmal sicher, ob diese Funktion gibt, was ich brauche). Ich habe auch versucht, (CFFI:MAKE-POINTER (CFFI:POINTER-ADDRESS *P*)), noch einmal ohne Erfolg zu tun.

This question schlägt vor, diesen Ansatz:

(cffi:with-foreign-object (p :pointer) 
      (setf (cffi:mem-ref p :pointer) (cvodecreate 1 2)) 
      (cvodefree p)) 

Dies funktioniert (zumindest es keinen Fehler werfen). Ich glaube, ich verstehe, wie es funktioniert: es schafft (ordnet den Speicher für) einen Zeiger-to-a-Zeiger P, deren MEM-REF (oder in C Bedingungen wäre dereferencing *p) durch das Ergebnis auf CVODECREATE gefüllt ist. Schließlich gebe ich diesen Zeiger an einen Zeiger an CVODEFREE weiter, der genau dieses erwartet. Schließlich wird der für P zugewiesene Speicher freigegeben, sobald das Formular beendet ist. Ist das der richtige Ansatz? Und ist es die einzige, die ich nehmen kann?

+0

Wäre sehr interessant zu wissen, warum sie diese Signatur für 'CVodeFree' gewählt haben. Scheint so, als würde man "über-engineering" machen und versuchen, besonders clever zu sein. –

+0

@DanielJour Soweit ich mich erinnere, ist dieser Weg in der C-Welt nicht ungewöhnlich. Vielleicht befreien sie den Speicher und NULL den Zeiger dort. Aber ich stimme zu, völlig unnötig. – mobiuseng

Antwort

2

Yup, sieht Ihr Ansatz richtig, hier ist ein kleiner Test, das Konzept zu zeigen, die gerade von dem ers ausgeführt werden können.

(let* (;; a float 
     (v0 32s0) 

     ;; a pointer to a float foreign memory 
     (p0 (cffi:foreign-alloc :float :initial-element v0))) 

    ;; a new pointer 
    (cffi:with-foreign-object (p1 :pointer) 

    ;; make the new pointer point to the first pointer 
    (setf (cffi:mem-aref p1 :pointer) p0) 

    ;; dereferencing twice should give you the original number 
    (cffi:mem-aref (cffi:mem-aref p1 :pointer) :float))) 

p.s.Ich bin mir sicher, dass du das inzwischen weißt, es hat so lange gedauert, bis du eine Antwort bekommen hast. Hoffentlich kann dies anderen helfen