The cffi.ss library of the compiler collection
implements a subset of Gambit-C's foreign-function
interface (see Marc Feeley's Gambit-C,
version 3.0). The cffi.ss module defines two forms:
c-lambda and c-declare. When interpreted directly or
compiled to byte code, c-lambda produces a function that
always raises exn:user, and c-declare raises
exn:user. When compiled by mzc, the forms provide access to
C. The mzc compiler implicitly imports cffi.ss into the
top-level environment.
The c-lambda form creates a Scheme procedure whose body is
implemented in C. Instead of declaring argument names, a
c-lambda form declares argument types, as well as a return
type. The implementation can be simply the name of a C function, as
in the following definition of fmod:
Alternatively, the implementation can be C code to serve as the body
of a function, where the arguments are bound to ___arg1
(three underscores), etc., and the result is installed into
___result (three underscores):
The c-lambda form provides only limited conversions between C and
Scheme data. For example, the following function does not reliably
produce a string of four characters:
because the representation of a float can contain null bytes,
which terminate the string. However, the full MzScheme API, which is
described in Inside PLT MzScheme, can be used in a function body:
The c-declare form declares arbitrary C code to appear after
escheme.h or scheme.h is included, but before any other
code in the compilation environment of the declaration. It is often
used to declare C header file inclusions. For example, a proper
definition of fmod needs the math.h header file:
The c-declare form can also be used to define helper C
functions to be called through c-lambda.
The plt/collects/mzscheme/examples directory in the PLT
distribution contains additional examples.
The c-lambda and c-declare forms are defined as follows:
(c-lambda (argument-type···) result-typefuncname-or-body-string)
creates a Scheme procedure whose body is implemented in C. The
procedure takes as many arguments as the supplied
argument-types, and it returns one value. If return-type
is void, the procedure's result is always void. The
funcname-or-body-string is either the name of a C function (or
macro) or the body of a C function.
If funcname-or-body-string is a string containing only
alphanumeric characters and _, then the created Scheme
procedure passes all of its arguments to the named C function (or
macro) and returns the function's result. Each argument to the Scheme
procedure is converted according to the corresponding
argument-type (as described below) to produce an argument to
the C function. Unless return-type is void, the C
function's result is converted according to return-type for the
Scheme procedure's result.
If funcname-or-body-string contains more than alphanumeric
characters and _, then it must contain C code to implement the
function body. The converted arguments for the function will be in
variables ___arg1, ___arg2, ... (with three
underscores in each name) in the context where the
funcname-or-body-string is placed for compilation. Unless
return-type is void, the funcname-or-body-string
code should should assign a result to the variable ___result
(three underscores), which will be declared but not initialized. The
funcname-or-body-string code should not return explicitly;
control should always reach the end of the body. If the
funcname-or-body-string code defines the pre-processor macro
___AT_END (with three leading underscores), then the
macro's value should be C code to execute after the value
___result is converted to a Scheme result, but before the
result is returned, all in the same block; defining
___AT_END is primarily useful for deallocating a string in
___result that has been copied by conversion. The
funcname-or-body-string code will start on a new line at the
beginning of a block in its compilation context, and
___AT_END will be undefined after the code.
Each argument-type must be one of the following:
bool
Scheme range: any value
C type: int
Scheme to C conversion: #f=> 0, anything else => 1
C to Scheme conversion: 0 =>#f, anything else =>#t
char
Scheme range: character
C type: char
Scheme to C conversion: character's ASCII value cast to signed byte
C to Scheme conversion: ASCII value from unsigned cast mapped to character
unsigned-char
Scheme range: character
C type: unsigned char
Scheme to C conversion: character's ASCII value
C to Scheme conversion: ASCII value mapped to character
signed-char
Scheme range: character
C type: signed char
Scheme to C conversion: character's ASCII value cast to signed byte
C to Scheme conversion: ASCII value from unsigned cast mapped to character
int
Scheme range: exact integer that fits into an int
C type: int
conversions: (obvious and precise)
unsigned-int
Scheme range: exact integer that fits into an unsigned int
C type: unsigned int
conversions: (obvious and precise)
long
Scheme range: exact integer that fits into a long
C type: long
conversions: (obvious and precise)
unsigned-long
Scheme range: exact integer that fits into an unsigned long
C type: unsigned long
conversions: (obvious and precise)
short
Scheme range: exact integer that fits into a short
C type: short
conversions: (obvious and precise)
unsigned-short
Scheme range: exact integer that fits into an unsigned short
C type: unsigned short
conversions: (obvious and precise)
float
Scheme range: real number
C type: float
Scheme to C conversion: number converted to inexact and cast to float
C to Scheme conversion: cast to double and encapsulated as an inexact number
double
Scheme range: real number
C type: double
Scheme to C conversion: number converted to inexact
C to Scheme conversion: encapsulated as an inexact number
char-string
Scheme range: string or #f
C type: char*
Scheme to C conversion: string => contained character array pointer, #f=>NULL
C to Scheme conversion: NULL=>#f, anything else => new string created by copying the string
nonnull-char-string
Scheme range: string
C type: char*
Scheme to C conversion: string's contained character array pointer
C to Scheme conversion: new string created by copying the string
scheme-object
Scheme range: any value
C type: Scheme_Object*
Scheme to C conversion: no conversion
C to Scheme conversion: no conversion
(pointerstring)
Scheme range: an opaque c-pointer value identified as type string or #f
C type: string*
Scheme to C conversion: #f=>NULL, c-pointer => contained pointer cast to string*
C to Scheme conversion: NULL=>#f, anything else => new c-pointer containing the pointer and identified as type string
The return-type must be void or one of the
arg-type keywords.
(c-declarecode-string)
declares arbitrary C code to appear after escheme.h or
scheme.h is included, but before any other code in the
compilation environment of the declaration. A c-declare form
can appear only at the top-level or within a module's top-level sequence.
The code-string code will appear on a new line in the file for
C compilation. Multiple c-include declarations are
concatenated (with newlines) in order to produces a sequence of
declarations.