ffi:c-inline
— Inline C code in a lisp form.
(ffi:c-inline
(lisp-value*)
(c-type*)
return-type
C-code
&key
one-liner
side-effects)
lisp-value | A lisp expression, evaluated. |
c-type | A valid FFI type. |
return-type | A valid FFI type or (VALUES) . |
C-code | A string with valid C code plus some valid escape forms. |
one-liner | A boolean, defaults to NIL. |
side-effects | A boolean, defaults to T. |
returns | One 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
et: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; n1++; } @(return 0)= out1; @(return 1)= out2; }" :side-effects nil))