CLisp 31:调用C程序之外部函数

定义一个外部函数,然后输入#’name看结果,#<FOREIGN-FUNCTION "C_FUN_NAME" #x10001030>,不同于FUNCTIONCOMPILED-FUNCTION

函数SYSTEM::%PUTD,输入一个名称和一个函数对象,相当于定义一个函数。例如(system::%putd 'foo #'(lambda (x y) (+ x y))),相当于(defun foo (x y) (+ x y))。宏ffi::def-call-out就用它生成函数,不过输入的函数对象不是lambda,而是FOREIGN-FUNCTION对象,该外部函数对象由函数ffi::find-foreign-function返回。

       函数ffi::find-foreign-functionDLL中找出指定名称的函数。输入6个参数,C函数名(字符串),函数类型(PARSE-C-FUNCTION返回的数组),properites(布尔),DLL文件名(字符串),版本号,未知参数(填NIL),返回外部函数对象。

 

       def-call-out的可选参数的作用:

       :NAME 外部函数的真实名称,即C语言的函数名,如果LISP中用的函数名和C语言中的函数名相同,则可以不指定。

       :ARGUMENTS 参数列表,形参名可以和C语言的不同,但参数顺序一定要相同。

       :LANGUAGE 该参数约定函数调用的规范,例如参数入栈的顺序,缺省是STDC

       :BUILT-IN 通常不用,采用“编译时静态链接”方式对接LISPC,才用到此参数。

       :LIBRARY DLL文件名。

       :VERSION 函数在DLL中的版本号,没用过。

       :DOCUMENTATION 函数注释。

 

       输入参数的传递方式,即调用C函数时怎样将参数压入堆栈。

       int:接受整形实参,将整数值压入堆栈。

       (c-ptr int):接受整形实参,先在堆栈开辟一块空间放整数值,再将空间地址压入堆栈。

       (c-ptr-null int):接受整形实参时同(c-ptr int),但也可以接受NIL代表空指针。

       (c-array int N):接受长度为N的整数数组,将数组中的整数一一压入堆栈。

       (c-ptr (c-array int N)):接受长度为N的整数数组,先在堆栈开辟一块空间,将数组复制到此空间,再将空间地址压入堆栈。

       (c-array-ptr int):和(c-ptr (c-array int N))相似,但不限制数组的长度。

       (c-pointer int):不接收LISP的整形变量,不接收FOREIGN-POINTER类型。接收c-var-address返回的FOREIGN-ADDRESS时,不校验所指对象的类型。接收c-var-object返回的FOREIGN-VARIABLE时,校验对象类型,必须是(:type int)类型。直接接收外部变量的名称时,校验对象类型,必须是(:type (c-pointer int))类型。不管接收什么,最终都将外部变量的地址压入堆栈。

       c-string:接受字符串实参,先在堆栈开辟一块空间,将字符串复制到此空间,再将空间地址压入堆栈。

       (c-ptr (c-array-max character 256)):和c-string相似。

(def-c-struct name (x int) (y int)):参数类型为结构体,会将结构体的各元素压入堆栈。

值得注意的时,LISP不会把其内部内存空间暴露给外部C函数,应该是为了安全。需要传变量地址时,例如c-ptrc-ptr-nullc-array-ptrc-string类型,就在堆栈上复制出一个对象来,再将复制对象的地址传给外部C函数。在堆栈复制对象是缺省的做法,也可以改成用malloc分配内存,再复制对象,修改类型描述(c-ptr int :in :malloc-free)。对于c-ptrc-ptr-nullc-array-ptrc-string以外的类型,系统会忽略参数:malloc-free

 

返回参数的传递方式,没有悬念,就是C语言返回参数的方式。需要研究的是,如果返回c-ptrc-ptr-nullc-array-ptrc-string类型,谁负责释放内存。如果在C函数中申请内存,希望在LISP中释放内存,应该将返回类型定义成(:return-type (c-ptr int) :malloc-free)。如果返回c-pointer类型,必须在LISP中显式释放内存。

 

LISP函数是可以返回多个值的,外部函数通过输出参数返回多个值。输出参数的传递方式,和输入参数是相似的。因为LISP要预留一块内存存放输出的内容,在堆栈上预留或者用malloc申请内存,需要确定内存的大小,所以c-stringc-array-ptrc-ptr-null这种不能确定大小的类型不能作为输出参数。需要字符串类型的输出参数,应该定义成(x (c-ptr (c-array-max character 256)))

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值