Duncan Temple Lang

University of California at Davis

Department of Statistics


The idea behind this package is to allow R programmers to dynamically invoke arbitrary compiled routines without having to explicitly write and compile C code to perform the invocation. This may not be of immense value as one has to compile the original routines to which you are interfacing. Furthermore, a compiled interface will be faster than one that examines its inputs at run-time. However, the dynamic interface is somewhat interesting.

The package is an interface to libffi. There are two main functions of interest to users. The first is prepCIF() which is used to create a "template" call to any native routine with a particular signature - both type of inputs and return value. Having created this interface object, we can use it to make one or more calls to any routine with that signature. We do this with callCIF() .

We specify the type of the return value and of each of the parameters in our call to prepCIF() . There are objects describing each of the basic types such as a double, various types of integers and pointers.

Table 1. 

R variabledescription
doubleTypea double in C
floatTypea float in C
longdoubleTypefor platforms that support a long double type
pointerTypea generic void * pointer
sint16Typea signed 16-bit/2 byte integer
sint32Typea regular signed 32-bit/4-byte integer
sint64Typea signed 64-bit integer
sint8Typea signed single byte integer
uint16Typean unsigned 16-bit integer
uint32Typean unsigned 32-bit integer
uint64Typean unsigned 64-bit integer
uint8Typean unsigned 8-bit integer
voidTypethe empty/void type of specific use when the routine of interest has no return value.
stringTypea type object introduced for this package for representing strings, i.e. char *. This might be expanded in the future for different types of strings, i.e. signed and unsigned characters, wide characters, etc.



In addition to these primtive types, one can create new types for describing C-level structs. See structType() .

Let's consider a very simple example of calling a C routine that takes no arguments and returns no value.

#include <stdio.h>
void
voidCall()
{
  fprintf(stderr, "In voidCall\n");
}


This is included in the compiled code loaded in the Rffi package. We would create a CIF for calling a routine with this signature via

+
void = prepCIF(voidType)

We only have to specify the return type. We don't have to specify any additional information as there are no parameters. Note that we don't specify the name of the C routine to call. This CIF can be used to call any routine with such a signature. And we can use it for multiple calls to the same or different routines.

So now we can call the C routine voidCall via callCIF() . We have to specify the CIF and the name of the routine.

+
 callCIF(void, "voidCall")

You'll see Again, since there are no inputs to this routine, we don't have to specify any.

Consider a C routine that takes no inputs and returns a real value:

double
rdouble()
{
    return(3.1415);
}


The same steps allow us to call this routine, but we need to specify the type of the return value differently.

+
cif = prepCIF(doubleType)
callCIF(cif, "rdouble")

This returns the value 3.1415 as an R numeric vector of length 1.

Passing Inputs

Let's move on to where we pass values from R to the native routine. We'll use a routine (also in Rffi.so/dll) called foo that takes an integer and a double. It returns a double - the sum of the two.

#include <stdio.h>
double
foo(int x, double y)
{
    fprintf(stderr, "In foo %d %lf\n", x, y);
    return(x + y);
}


To create the CIF, we need to specify the return type as doubleType and then a list of the parameter types. These are sint32Type and doubleType. Since there are various different types of integers, we have to be specific about which one is to be used. We use a regular 4-byte/32-bit integer that has a bit for sign so that negative values are possible. So our call is

+
cif = CIF(doubleType, list(sint32Type, doubleType))

And now we can the routine with

+
callCIF(cif, "foo", -1L, pi)

What if we passed a numeric value instead of an integer for the first argument? For example,

+
callCIF(cif, "foo", -1.3, pi)

In the current version of the code, the numeric value is coerced to the target type - an integer. As a result, the value -1 is passed to the native routine.

What about if we pass a string such as "abc"? This is coerced to an integer and results in a NA.

Pointers and Arrays

Next we turn our attention to passing non-scalar values, specifically pointers. We'll deal with structures later. Consider a routine which takes a collection of real values via a pointer of type double. It also takes the number of elements as an unsigned integer. The routine retPointer provides such a routine in test.c and available in the Rffi. We can create CIF

+
cif = CIF(pointerType, list(pointerType, uint32Type))

noting that it returns a new array of doubles. We can then invoke this with

+
x = c(1, 2, 3, 4)
y = callCIF(cif, "retPointer", x, length(x))

The resulting value in y is an external pointer which contains the address of the returned array newly allocated in retPointer. We can pass this to another native routine. Alternatively, we can call native code to extract values and generally manipulate it. We might do this with a regular hand-built routine that is invokable from R via the .Call() interface as we are dealing with SEXP objects throughout, i.e. inputs and outputs. One such routine is contained in test.c - R_copyDoubleArray. We call it with the external pointer to the double * and the number of elements, e.g.

+
val = .Call("R_copyDoubleArray", y$value, length(x))

If we wanted to release the memory associated with the array, we could call free. Again, we could use a manually created routine via .Call() . But we can also do it via libffi.

+
free.cif = CIF(voidType, list(pointerType))
callCIF(free.cif, "free", y$value)

Structures

libffi also allows us to work with structures. Consider a simple structure defined as

typedef struct {
    short s;
    int i;
    double d;
    char *string;
} MyStruct;


Next, consider a routine that returns an instance of this structure.

char *MyString = "a string";
MyStruct
getStruct()
{
    MyStruct c = {-1, 11, 99.2};
    c.string = MyString;
    return(c);
}


How can we call this from R and get the structure back? We start by defining a new type to describe this structure. We use structType() for this. We give a list of the types of the elements within the structure.

+
myStruct.type = structType(list(s = sint16Type, i = sint32Type, d = doubleType, str = stringType))

Note that the short corresponds to the sint16 type.

We can optionally provide names. It is a good idea if we know them as we use the same names as in the C code to simplify interaction. At present we don't use the names, but we may in the future.

Now that we have this type information, we can use it as we did the regular built-in types, e.g. doubleType. So we create our CIF to call the routine getStruct:

+
cif = CIF(myStruct.type)

And now we can call this

+
callCIF(cif, "getStruct")

The result is an R list with 4 elements corresponding to the elements of the C structure.

Now let's explore passing an R object to a routine that expects a structure. We can use the following routine

void
doStruct(MyStruct s)
{
    fprintf(stderr, "doStruct: s = %d, i = %d, d = %lf, string = %s\n", 
                      (int) s.s, s.i, s.d, s.string);
}


We create the CIF for this routine

+
cif = CIF(voidType, list(myStruct.type))

Now we can calls this as

+
callCIF(cif, "doStruct", list(-1L, 1L, 3.1415, "R string"))

Future Possibilities & Directions

At present, we have not added support for specifying the type of the pointer, e.g. a pointer to a double. This is entirely feasible and would be valuable as it provides a great deal more information. This can then be used to comprehend the contents of the values with more specificity.

Information about routines can be obtained via RGCCTranslationUnit. This can be used within the same R session to construct CIF objects for different routines.