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))