读书人

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

发布时间: 2013-01-23 10:44:50 作者: rapoo

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

用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-VALUE是Common 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-object和with-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。窃以为它是为转换编码格式而设计的。

读书人网 >编程

热点推荐