ffi:c-inline — Inline C code in a lisp form.

Special form

(ffi:c-inline (lisp-value*) (c-type*) return-type C-code &key one-liner side-effects)

lisp-valueA lisp expression, evaluated.
c-typeA valid FFI type.
return-typeA valid FFI type or (VALUES).
C-codeA string with valid C code plus some valid escape forms.
one-linerA boolean, defaults to NIL.
side-effectsA boolean, defaults to T.
returnsOne or more lisp values.


This is an special form which can be only used in compiled code and whose purpose is to execute some C code getting and returning values from and to the lisp environment.

The first argument to ffi:c-inline is a list of lisp forms. These forms are going to be evaluated and their lisp values will be transformed to the corresponding C types denoted by c-type.

The input values are used to create a valid C expression using the template in C-code. This is a string of arbitrary size which mixes C expressions with two kind of escape forms.

The first kind of escape form are made of a hash and a letter or a number, as in: #0, #1, ..., until #z. These codes are replaced by the corresponding input values. The second kind of escape form has the format @(return [n]), it can be used as lvalue in a C expression and it is used to set the n-th output value of the ffi:c-inline form.

When the parameter one-liner is true, then the C template must be a simple C statement that outputs a value. In this case the use of @(return) is not allowed. When the parameter one-liner is false, then the C template may be a more complicated block form, with braces, conditionals, loops and spanning multiple lines. In this case the output of the form can only be set using @(return).

Note that the conversion between lisp arguments and FFI types is automatic. Note also that ffi:c-inline cannot be used in interpreted or bytecompiled code!


The following example implements the transcendental function SIN using the C equivalent

(ffi:c-lines "#include <math.h>")
(defun mysin (x)
  (ffi:c-inline (x) (:double) :double "sin(#0)" :one-liner t :side-effects nil))

This function can also be implemented using the @(return) form as follows:

(defun mysin (x)
  (ffi:c-inline (x) (:double) :double "@(return)=sin(#0);" :side-effects nil))

The following example is slightly more complicated as it involves loops and two output values:

(defun sample (x)
  (ffi:c-inline (n1 n2) (:int :int) (values :int :int) "{
    int n1 = #0, n2 = #1, out1 = 0, out2 = 1;
    while (n1 <= n2) {
      out1 += n1;
      out2 *= n1;
    @(return 0)= out1;
    @(return 1)= out2;
   :side-effects nil))