Next: , Previous: Optimizing Type Translators, Up: Foreign Types


6.6 Foreign Structure Types

For more involved C types than simple aliases to built-in types, such as you can make with defctype, CFFI allows declaration of structures and unions with defcstruct and defcunion.

For example, consider this fictional C structure declaration holding some personal information:

  struct person {
    int number;
    char* reason;
  };

The equivalent defcstruct form follows:

  (defcstruct person
    (number :int)
    (reason :string))

By default, convert-from-foreign (and also mem-ref) will make a plist with slot names as keys, and convert-to-foreign will translate such a plist to a foreign structure. A user wishing to define other translations should use the :class argument to defcstruct, and then define methods for translate-from-foreign and translate-into-foreign-memory that specialize on this class, possibly calling call-next-method to translate from and to the plists rather than provide a direct interface to the foreign object. The macro translation-forms-for-class will generate the forms necessary to translate a Lisp class into a foreign structure and vice versa.

Please note that this interface is only for those that must know about the values contained in a relevant struct. If the library you are interfacing returns an opaque pointer that needs only be passed to other C library functions, by all means just use :pointer or a type-safe definition munged together with defctype and type translation. To pass or return a structure by value to a function, load the cffi-libffi system and specify the structure as (:struct structure-name). To pass or return the pointer, you can use either :pointer or (:pointer (:struct structure-name)).

Compatibility note: Previous versions of CFFI accepted the “bare” structure-name as a type specification, which was interpreted as a pointer to the structure. This is deprecated and produces a style warning. Using this deprecated form means that mem-aref retains its prior meaning and returns a pointer. Using the (:struct structure-name) form for the type, mem-aref provides a Lisp object translated from the structure (by default a plist). Thus the semantics are consistent with all types in returning the object as represented in Lisp, and not a pointer, with the exception of the “bare” structure compatibility retained. In order to obtain the pointer, you should use the function mem-aptr.

See defcstruct for more details.