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?
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. –
@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