Chapter 2

Foreign-Function Interface to C

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:

(define fmod (c-lambda (double double) double "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):

(define machine-string->float
  (c-lambda (char-string) float
     "___result = *(float *)___arg1;"))

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:

(define broken-machine-float->string
  (c-lambda (float) char-string
     "char b[5]; *(float *)b = ___arg1; b[4] = 0; ___result = b;"))

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:

(define machine-float->string
  (c-lambda (float) scheme-object
     "char b[4]; *(float *)b = ___arg1; ___result = scheme_make_sized_string(b, 4, 1);"))

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:

(c-declare "#include <math.h>")
(define fmod (c-lambda (double double) double "fmod"))

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: