4 Functions and Callbacks
dxtr edited this page 2026-10-18 15:16:26 +02:00

Functions and Callbacks

defcfun

(ffi:defcfun ("FT_Load_Glyph" ft-load-glyph) ft-error
  "Load glyph INDEX of FACE into its slot."
  (face :pointer)
  (index :uint)
  (flags load-flags))

(defcfun ("c_name" lisp-name) result-type [docstring] (argument type)...) defines a function that converts its arguments as their types say, calls the C function, and converts the result, or returns no values for :void. Without a docstring, the function's says which C function it calls. Its ftype is declaimed from the types, so SBCL checks the arguments, at compile time where it can. The C name is looked up in every library loaded.

A :string argument takes a Lisp string, copied for the call and freed after it, or a pointer as it is. A :string result is a Lisp string, or nil for a null pointer. (:string :encoding :utf-16le) does the same in UTF-16LE, and so for the other encodings; see Strings.

(foreign-type-lisp-type type) gives the Lisp type of the values an argument of type takes, and (foreign-type-lisp-type type :result) the values type of a call whose result is type: what defcfun declaims, for a binding made by other means that declaims the same.

(ffi:foreign-type-lisp-type :int32)            ; => (SIGNED-BYTE 32)
(ffi:foreign-type-lisp-type :string)           ; => (OR STRING FFI:FOREIGN-POINTER)
(ffi:foreign-type-lisp-type :string :result)   ; => (VALUES (OR NULL STRING) &OPTIONAL)
(ffi:foreign-type-lisp-type :void :result)     ; => (VALUES &OPTIONAL)

Calls without a definition

(ffi:foreign-funcall "abs" :int -3 :int)                         ; => 3
(ffi:foreign-funcall-pointer (ffi:foreign-symbol-pointer "abs") :int -4 :int)
(ffi:foreign-funcall "free" :pointer (ffi:null-pointer))        ; :VOID, no values

foreign-funcall calls by name and foreign-funcall-pointer through a pointer: types and arguments in turn, then the result type, :void if it is left out. With numbers and pointers they allocate nothing. foreign-symbol-pointer returns a pointer to a C function or variable, or nil.

Variadic functions

(ffi:with-foreign-pointer-as-string ((buffer size) 64)
  (ffi:foreign-funcall-varargs "snprintf" (:pointer buffer :size size :string "%d %.2f")
                               :int 42 :double 1.5d0 :int))
;; => "42 1.50"

The fixed arguments go in a list, and the variable ones after it, promoted as C promotes them: a float to a double, an integer narrower than int to int. They are passed as the platform's convention for variable arguments asks, on Windows too; see Platforms and Testing.

Callbacks

(ffi:defcallback on-message :void ((level :int) (text :string))
  ;; Only record the message, on a queue the program drains later.
  (record-message level text))

(set-log-function (ffi:callback on-message))

defcallback defines a function C can call; callback, with the name unevaluated, and get-callback return the pointer to give C. Arguments and the result convert as their types say: a parameter of a string type is read in its encoding. A callback cannot return a string type.

Nothing may unwind through C frames. A callback must not let a condition or a non-local exit out of its body: it records what it was told and returns, and the program handles it later. A callback runs on the thread the C code calls it on, which SBCL allows for threads C started.

errno

(errno) returns the errno the last foreign call left. Read it right after the call whose failure it explains: any other foreign call may change it. On Windows it is the errno of msvcrt, the C library calls by name reach there.

The floating-point environment

SBCL unmasks the floating-point traps for invalid operations, division by zero and overflow; C code assumes them masked. with-foreign-float-environment masks every trap for the extent of its body and restores the Lisp's own after, allocating nothing. Call C code that computes with floats inside it: a GPU driver, for one, may start threads that inherit the environment of the thread that starts them.