2016-03-07 18 views
5

Tôi đang cố gắng viết trình bao bọc CFFI cho thư viện Sundials CVODE. SWIG đã bị nghẹt thở trên các tiêu đề Sundials vì chúng khá liên kết với nhau và SWIG không thể tìm thấy các tiêu đề phù hợp, vì vậy tôi đã làm nó bằng tay: một chút mất thời gian nhưng tôi đã quản lý.Common Lisp CFFI: con trỏ đến con trỏ

Bây giờ tôi đang cố gắng kiểm tra xem nó có hoạt động chính xác hay không. Bây giờ, chỉ đơn giản là tạo ra "đối tượng vấn đề" và xóa nó. Đó là nơi mà vấn đề bắt đầu. Vì vậy, "Vấn đề đối tượng" được phân bổ thông qua chức năng

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

Đối với mà tôi đã tạo ra wrapper:

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

PS. SUNDIALS_EXPORT (ít nhất là trên Unix) về cơ bản là không có gì.

Bây giờ, để tiêu diệt các đối tượng, sundials sử dụng chức năng riêng của nó:

SUNDIALS_EXPORT void CVodeFree(void **cvode_mem); 

Vì vậy, tôi cần phải vượt qua nó tham chiếu đến các đối tượng được tạo ra bởi CVodeCreate. Trong C, nếu bộ nhớ của tôi không phải là lỗi, tôi sẽ làm một cái gì đó như CVodeFree(&problem_object). Trong CL Tôi đã viết trình bao bọc này cho hàm:

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

Vì vậy, tại đây COVDE-MEM là con trỏ trỏ tới con trỏ. Câu hỏi là làm thế nào để có được con trỏ của con trỏ trong CL/CFFI? Đây là sự khởi đầu của mã:

(defvar *p* (cvodecreate 1 2)) 

(. PS Đừng lo lắng về những con số truyền cho CVODECREATE, họ chỉ nói mà phương pháp sử dụng, vẫn cần phải hằng định nghĩa để làm cho nó dễ đọc hơn)

Vì vậy *P* là một cái gì đó giống như

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

Nếu tôi vượt qua nó trực tiếp đến CVODEFREE, nó kết thúc trong lỗi:

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

Tôi đã thử vượt qua (CFFI:POINTER-ADDRESS *P*) nhưng kết quả là "lỗi bus ..." tương tự (thậm chí không chắc chắn nếu hàm này trả về những gì tôi cần). Tôi cũng đã cố gắng làm (CFFI:MAKE-POINTER (CFFI:POINTER-ADDRESS *P*)), một lần nữa mà không thành công.

This question cho thấy phương pháp này:

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

này hoạt động (ít nhất là nó không ném ra một lỗi). Tôi nghĩ rằng tôi hiểu cách nó hoạt động: nó tạo ra (cấp phát bộ nhớ cho) một con trỏ tới một con trỏ P, có MEM-REF (hoặc trong C sẽ là dereferencing *p) được điền vào kết quả theo số CVODECREATE. Cuối cùng, tôi sẽ chuyển con trỏ tới con trỏ này tới số CVODEFREE, điều này hy vọng chính xác điều này. Cuối cùng, bộ nhớ được phân bổ cho P được giải phóng sau khi biểu mẫu kết thúc. Đây có phải là cách tiếp cận chính xác không? Và đó là người duy nhất tôi có thể làm?

+0

Sẽ rất thú vị khi biết tại sao họ chọn chữ ký đó cho 'CVodeFree'. Có vẻ như "quá kỹ thuật" và cố gắng trở nên thông minh hơn. –

+0

@DanielJour Theo tôi nhớ theo cách này không phải là bất thường trong C-thế giới. Có lẽ, họ giải phóng bộ nhớ và NULL con trỏ ở đó. Nhưng tôi đồng ý, hoàn toàn không cần thiết. – mobiuseng

Trả lời

2

Yup, cách tiếp cận của bạn có vẻ đúng, đây là một thử nghiệm nhỏ để hiển thị khái niệm có thể chạy thẳng từ bản repl.

(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.Tôi chắc rằng bạn biết điều này ngay bây giờ, xin lỗi phải mất quá lâu để có được bạn một câu trả lời. Hy vọng rằng điều này có thể giúp người khác

Các vấn đề liên quan