Types
A type specifier names how a value is laid out in C and what Lisp sees of it. A constant specifier is parsed at compile time, so the code that uses it holds only the memory access and the conversion; a specifier known only at run time works too, more slowly.
Scalars
| Specifier | Size | Lisp values |
|---|---|---|
:int8 :uint8 :int16 :uint16 :int32 :uint32 :int64 :uint64 |
1 to 8 | integers |
:char :unsigned-char :uchar |
1 | integers; :char is signed, as in cffi |
:short :unsigned-short :ushort |
2 | integers |
:int :unsigned-int :uint |
4 | integers |
:long :unsigned-long :ulong |
8, or 4 on Windows | integers |
:long-long :llong :unsigned-long-long :ullong |
8 | integers |
:size :ssize :intptr :uintptr :ptrdiff |
8 | integers |
:float :double |
4, 8 | single and double floats |
:pointer |
8 | pointers |
:string |
8 | Lisp strings in UTF-8, in calls only (see Strings) |
(:string :encoding encoding) |
8 | Lisp strings in :utf-16le, :utf-16be or :latin-1, in calls only |
:boolean, (:boolean integer-type) |
that of the integer type, :int by default |
generalized booleans: 0 is false, any other value true, and true is written as 1 |
:void |
none | a function's result only |
Each scalar is aligned to its size.
Typedefs
(ffi:defctype ft-pos :long "A coordinate, in font units or 26.6 pixels.")
defctype names a type that is stored and converted as its base type.
Enums
(ffi:defcenum render-mode (:normal 0) :light :mono)
(ffi:defcenum (small :int8) (:minus -1) :zero)
An enum's values are keywords to Lisp. Each item is a keyword, or
(keyword value); a keyword without a value takes the one after the
previous keyword's, the first 0. Without a base type an enum is :uint32,
or :int32 if a value is negative, as in cffi.
A call, mem-ref and foreign-slot-value convert keywords to values and
back. An integer passes as itself. Reading a value no keyword has signals
an ffi-error; of a value two keywords share, the last defined is
returned.
foreign-enum-value, foreign-enum-keyword and
foreign-enum-keyword-list convert by hand; the first two take
:errorp nil to return nil in place of an error.
Bitfields
(ffi:defbitfield (load-flags :int32) (:no-scale 1) (:no-hinting 2) :render)
(ffi:foreign-bitfield-value 'load-flags '(:no-scale :render)) ; => 5
(ffi:foreign-bitfield-symbols 'load-flags 3) ; => (:NO-SCALE :NO-HINTING)
A bitfield's values are lists of symbols. Each item is a symbol, or
(symbol mask); a symbol without a mask takes the next bit above the
highest single-bit mask so far, the first 1. Writing takes a list of
symbols, one symbol, or an integer; reading gives the symbols of the
single bits set, in the order of the bits, and leaves out masks of several
bits. foreign-bitfield-symbol-list lists the symbols in the order of
their definition.
Structs and unions
(ffi:defcstruct ft-vector (x :long) (y :long))
(ffi:defcstruct glyph-metrics
"Some of FT_Glyph_Metrics."
(width :long) (height :long)
(bearing (:struct ft-vector)) ; held by value
(tags :uint8 :count 4)) ; an array of 4
(ffi:defcunion value (i :int64) (d :double))
Type specifiers name them (:struct name) and (:union name). Slots are
laid out as C lays them out, the same on x86-64 System V, Windows x64 and
AArch64: each slot at the next multiple of its alignment, the struct
aligned as its most aligned slot and its size rounded up to a multiple of
that. A union's slots all start at 0. A struct held by value must be
defined before the struct that holds it.
| Operator | Gives |
|---|---|
(foreign-slot-value pointer type slot) |
the value of a scalar slot; setf writes it |
(foreign-slot-pointer pointer type slot) |
a pointer to a slot: to the first element of an array, or to a struct |
(foreign-slot-offset type slot) |
the slot's offset in bytes |
(foreign-slot-type type slot) |
the type the slot was defined with; an array's element type |
(with-foreign-slots (variables pointer type) body...) |
variables that stand for slots: a symbol for the slot of its name, (variable slot) for another |
(foreign-type-size type), (foreign-type-alignment type) |
the size, padding included, and the alignment |
(foreign-type-lisp-type type &optional direction) |
the Lisp type a call takes for an argument of type, or with :result the values type it returns, as defcfun declaims them |
foreign-slot-value reads scalar slots only. An array, struct or union
slot has no value to read, and asking for one is refused, at compile time
when the type and slot are constants: take its pointer with
foreign-slot-pointer.
C bit-fields have no slot kind of their own: define their storage unit as
an integer slot and take the fields out with ldb.