CLisp 30:调用C程序之外部变量

来源:互联网 发布:linux 定时重启服务器 编辑:程序博客网 时间:2024/05/21 22:44

       def-c-var定义的外部变量,其本质是一个宏,Symbol Macro。定义一个外部变量,然后执行(macroexpand ‘name),得到(FOREIGN-VALUE (LOAD-TIME-VALUE (GET 'NAME 'FOREIGN-VARIABLE)))

       (GET 'NAME 'FOREIGN-VARIABLE)的作用是获取符号NAME的属性FOREIGN-VARIABLE。在Common Lisp中,每个符号都有一个属性列表,按key+value的方式存储任意的属性。

       (setf (get 'symbol-name 'attr-name) attr-value)   保存一个属性

       (get 'symbol-name 'attr-name)     获取一个属性,失败时返回NIL

       也可以调用(system::%put 'symbol-name 'attr-name attr-value)保存一个属性

       调用def-c-var宏时,会创建一个FOREIGN-VARIABLE对象,保存到符号NAME的属性列表中,前面的GET取到的就是此对象。

       LOAD-TIME-VALUECommon Lisp提供的一种机制,推迟计算输入参数的值的时间。对交互式执行没有影响,影响编译式执行。这里不展开,就当它不存在吧。

       FOREIGN-VALUE用于计算外部对象的值,以LISP对象的形式返回。

 

       看到这里,应该明白为什么要用setf,而不是setq来改变外部变量的值了。改变数组元素的值,必须用(setf (element NAME i) value),其道理是相同的,因为element也是一个宏,查看其展开形式就会明白奥秘所在。下面看一下各宏的展开形式,将相同的部分合在一起,形成一棵树,即各函数调用关系组成的树,等号后面就是对外开放的宏名(或函数名)。

(GET 'NAME 'FOREIGN-VARIABLE))

       LOAD-TIME-VALUE == c-var-object

              FOREIGN-VALUE == name

              FOREIGN-ADDRESS == c-var-address

              FOREIGN-POINTER返回外部指针类型

              VALIDP 如果DLL被关闭就返回NIL

              FOREIGN-TYPE

                     DEPARSE-C-TYPE == typeof

                     %SIZEOF == sizeof

                     %BITSIZEOF == bitsizeof

              %ELEMENT

                     FOREIGN-VALUE == element

              %DEREF

                     FOREIGN-VALUE == deref

              %SLOT

                     FOREIGN-VALUE == slot

              %CAST

                     FOREIGN-VALUE == cast

              %OFFSET

                     FOREIGN-VALUE == offset

      

       还有四个WITH类型的宏。

 

(FFI:WITH-C-VAR (var c-type [initarg]) body):创建一个c-type类型的外部变量var,在代码体中可以使用变量var。注意c-type前面必须加单引号。在body中使用的var不是标号宏,而是函数参数,宏with-c-var会生成临时函数(lambda (var) body)。下面方法查看var到底是什么:

(with-c-var (var 'int 128)

(format t “~S~%”(c-var-address var))

(format t “~S~%”(c-var-object var))) =>

#<FOREIGN-ADDRESS #x0022B370>

#<FOREIGN-VARIABLE "EXEC-ON-STACK" #x0022B370>

 

(FFI:WITH-FOREIGN-OBJECT (var c-type [initarg]) body):和with-c-var基本相同,不同的是var的类型。下面方法查看var到底是什么,返回结果和上面例子相同。

(with-c-var (var 'int 128)

(format t “~S~%” (foreign-address var))

(format t “~S~%” var))) =>

#<FOREIGN-ADDRESS #x0022B370>

#<FOREIGN-VARIABLE "EXEC-ON-STACK" #x0022B370>

 

(FFI:WITH-C-PLACE (var foreign-entity) body):要求在外边创建好一个FOREIGN-VARIABLE类型的实体foreign-entity,将其转换成外部变量var。可以组合with-foreign-objectwith-c-place得到with-c-var的效果。

(with-foreign-object (obj ‘int 128)

       (with-c-place (var obj)

       (format t “~S~%”(c-var-address var))

(format t “~S~%”(c-var-object var)))) =>

#<FOREIGN-ADDRESS #x0022B370>

#<FOREIGN-VARIABLE "EXEC-ON-STACK" #x0022B370>

 

(FFI:WITH-FOREIGN-STRING (foreign-address char-count byte-count string &KEY encoding null-terminated-p start end) &BODY body):将一个LISP字符串string转换成外部变量,并按指定的编码格式encoding进行转换,提供外部地址foreign-address、字符个数char-count、字节个数byte-count三个变量给代码体body。窃以为它是为转换编码格式而设计的。

原创粉丝点击