Я пытаюсь написать оболочку CFFI для библиотеки Sundials CVODE. SWIG задыхался от заголовков солнечных часов, так как они довольно взаимосвязаны, и SWIG не мог найти правильные заголовки, поэтому я сделал это вручную: немного трудоемко, но я справился.
Теперь я пытаюсь проверить, правильно ли он работает. А пока просто создайте «проблемный объект» и удалите его. Вот где проблема начинается. Итак, "проблемный объект" выделяется через функцию
SUNDIALS_EXPORT void *CVodeCreate(int lmm, int iter);
Для чего я создал обертку:
(cffi:defcfun "CVodeCreate" :pointer
(lmm :int)
(iter :int))
PS. SUNDIALS_EXPORT
(по крайней мере, в Unix) ничего не значит.
Теперь для уничтожения объекта Солнечные часы используют собственную функцию:
SUNDIALS_EXPORT void CVodeFree(void **cvode_mem);
Итак, мне нужно передать ему ссылку на объект, созданный CVodeCreate
. В C, если моя память не виновата, я бы сделал что-то вроде CVodeFree(&problem_object)
. В CL я написал эту оболочку для функции:
(cffi:defcfun "CVodeFree" :void
(cvode-mem :pointer))
Итак, здесь COVDE-MEM
— это указатель на указатель. Вопрос как получить указатель указателя в CL/CFFI? Вот начало кода:
(defvar *p* (cvodecreate 1 2))
(PS. Не беспокойтесь о числах, переданных в CVODECREATE
, они просто говорят, какие методы использовать, все еще нужно определить константы, чтобы сделать его более читаемым)
Так что *P*
это что-то вроде
#.(SB-SYS:INT-SAP #X7FFFE0007060)
Если я передам его напрямую CVODEFREE
, это закончится ошибкой:
CL-USER> (cvodefree *p*)
; Evaluation aborted on #<SIMPLE-ERROR "bus error at #X~X" {1005EC9BD3}>.
Я пытался передать (CFFI:POINTER-ADDRESS *P*)
, но это приводит к похожей "ошибке шины..." (даже не уверен, возвращает ли эта функция то, что мне нужно). Я также пытался сделать (CFFI:MAKE-POINTER (CFFI:POINTER-ADDRESS *P*))
, но снова безуспешно.
Этот вопрос предлагает такой подход:
(cffi:with-foreign-object (p :pointer)
(setf (cffi:mem-ref p :pointer) (cvodecreate 1 2))
(cvodefree p))
Это работает (по крайней мере, это не выдает ошибку). Я думаю, что понимаю, как это работает: он создает (выделяет память) указатель на указатель P
, чей MEM-REF
(или в терминах C будет разыменование *p
) заполняется результатом CVODECREATE
. Наконец, я передаю этот указатель на указатель CVODEFREE
, который ожидает именно этого. Наконец, память, выделенная для P
, освобождается после завершения формы. Это правильный подход? И это единственное, что я могу взять?
CVodeFree
. Похоже на чрезмерную инженерию и попытку быть очень умным. - person Daniel Jour   schedule 07.03.2016