Name

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.

Description

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 et:c-inline cannot be used in interpreted or bytecompiled code!

Examples

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;
      n1++;
    }
    @(return 0)= out1;
    @(return 1)= out2;
    }"
   :side-effects nil))