define-c-struct name-and-options &rest descriptions => list
name-and-options ::= name | (name option*)
option::= (:foreign-name string) | (:forward-reference-p forward-reference-p)
descriptions ::= {slot-description | byte-packing | aligned}*
slot-description ::= {slot-name | (slot-name slot-type)}
A symbol naming the new structure type specifier
A string specifying the foreign name of the structure.
A symbol, or a list of symbol and type description, naming a slot in the structure
A symbol naming the slot
The foreign type of the slot
A list specifying byte packing for the subsequent slots
The number of 8-bit bytes to pack
The macro define-c-struct
is used to define a FLI structure type specifier, which corresponds to the C struct
type. It is a convenience function, as a structure type could also be defined using define-foreign-type.
A structure is an aggregate type, or collection, of other FLI types. The types contained in a structure are referred to as slots, and can be accessed using the foreign-slot-type and foreign-slot-value functions.
Some C compilers support pragmas such as
#pragma pack(1)
which causes fields in a structure to be aligned on a byte boundary even if their natural alignment is larger. This can be achieved from Lisp by specifying suitable byte-packing forms in the structure definition, as in the example below. Each byte-packing form specifies the packing for each slot-description that follows it in the define-c-struct
form. It is important to use the same packing as the C header file containing the foreign type.
An aligned form specifies that the next slot must be aligned on nbytes bytes. Note that this affects only the alignment of the next slot. It does not affect the length of the slot, or the alignment of other slots. You will need this when the slot is made to be aligned, for example in gcc
a slot defined like this:
int slot_name __attribute__ ((aligned (16))) ;
needs to be aligned on 16 bytes, even though the native alignment of the type int
is 4.
When forward-reference-p is true, the new type specifier is defined as a forward reference type and descriptions can be empty. See define-foreign-forward-reference-type.
The first example shows a C structure definition and the corresponding FLI definition:
struct a-point {
int x;
int y;
byte color;
char ident;
};
(fli:define-c-struct a-point (x :int)
(y :int)
(color :byte)
(ident :char))
The second example shows how you might retrieve data in Lisp from a C function that returns a structure:
struct 3dvector
{
float x;
float y;
float z;
}
static 3dvector* vector;
3dvector* fn ()
{
return vector;
}
(fli:define-c-struct 3dvector
(x :float)
(y :float)
(z :float))
(fli:define-foreign-function fn ()
:result-type (:pointer (:struct 3dvector)))
(let ((vector (fn)))
(fli:with-foreign-slots (x y z) vector
(values x y z)))
Finally an example to illustrate byte packing. This structure will require 4 bytes of memory because the field named a-short will be aligned on a 2 byte boundary and hence a byte will be wasted after the a-byte field:
(fli:define-c-struct foo ()
(a-byte (:unsigned :byte))
(a-short (:unsigned :short)))
After adding the byte-packing form, the structure will require only 3 bytes:
(fli:define-c-struct foo
(:byte-packing 1)
(a-byte (:unsigned :byte))
(a-short (:unsigned :short)))
define-c-enum
define-c-typedef
define-c-union
define-foreign-type
foreign-slot-names
foreign-slot-type
foreign-slot-value
FLI Types
LispWorks Foreign Language Interface User Guide and Reference Manual - 29 Sep 2017