Bindat 类型表达式并不局限于前面介绍的类型。它们也可以是返回 Bindat 类型表达式的任意 Lisp 表达式。例如,下面的类型描述了一种可以包含 24 位错误码或字节向量的数据结构:
(bindat-type (len u8) (payload . (if (zerop len) (uint 24) (vec (1- len)))))
此外,虽然复合类型通常解包为(并从)关联列表进行打包,但可以通过以下特殊关键字参数改变这一行为:
:unpack-val exp如果字段列表以该关键字结尾,那么解包时返回的值是 exp 的值,而非标准的关联列表。 exp 可以通过名称引用所有前面的字段。
:pack-val exp如果某个字段的类型后面跟有该关键字,那么打包到该字段的值由 exp 返回,而非从关联列表中提取。
:pack-var name如果字段列表以该关键字开头,那么后续所有 :pack-val 参数都可以通过名为 name 的变量
引用要打包到该复合类型的整体值。
例如,可以这样描述一个 16 位有符号整数:
(defconst sint16-bindat-spec
(let* ((max (ash 1 15))
(wrap (+ max max)))
(bindat-type :pack-var v
(n uint 16 :pack-val (if (< v 0) (+ v wrap) v))
:unpack-val (if (>= n max) (- n wrap) n))))
其行为如下:
(bindat-pack sint16-bindat-spec -8)
⇒ "\377\370"
(bindat-unpack sint16-bindat-spec "\300\100")
⇒ -16320
最后,你可以使用 bindat-defmacro 定义可在 Bindat 类型表达式中使用的新 Bindat 类型形式:
定义一个名为 name、参数为 args 的新 Bindat 类型表达式。
其行为与 defmacro 类似,重要区别是新定义的形式只能在 Bindat 类型表达式内部使用。