Back

Splus to C Interfacing

Splus Guides and Release Notes:     Unix/Linux     Windows


Updated for use with Splus 6.0, and R 1.5.1

--------------------------------------------------------
STEP (1): Write a C program. Here is an example:

% cat add.c

#include "stdio.h"
#include "math.h"
#include "stdlib.h"

#define PI 3.14159
#define NMAX 100     

void add(double *x, double *y, long *nn, double *out) {
  long n = *nn;
  int i;
  for(i=0;i<n;i++) *(out+i) = *(x+i) + *(y+i);
  /* for (i=0;i<n;i++) out[i] = x[i] + y[i]; */
}



Note 1: All arguments must be pointers.

Note 2: Any variable that is integer in S must be long in C [Nb., in
        gcc on linux, int's and long's are the same, so this matters
        less].

Note 3: It is recommended that the return type of the C function be
        "void" but it doesn't seem to matter much.

----------------------------------------------------------
STEP (2): Compile it using the appropriate command:

For Splus:
==========

linux% Splus CHAPTER add.c   # This will APPEND onto any existing
                             # makefile.  Only need to do it once
                             # per function that you are creating

                             # This also creates a local .Data
                             # directory to store variables in.  If
                             # you do not want this, say "rm -R .Data"
                             # before going on...
			       


linux% Splus make            # do this every time you change the .c
                             # file...

For R:
======

linux% R CMD SHLIB add.c     # do this every time you change the .c
                             # file...



----------------------------------------------------------
STEP (3): Link it into Splus/R using the appropriate command:

For Splus:
==========

> dyn.open("S.so")   # can be skipped if you keep the local .Data
                     #  directory from Splus CHAPTER add.c

For R:
======

> dyn.load("add.so")     #  This is the default name but it can be changed.




----------------------------------------------------------
STEP (4): Write an S function as follows:

    [ this is called a "wrapper function"; it just 
      smooths the rough edges between Splus/R and C ]


add.fun = function(x,y){
  n   = length(x)
  out = as.double(rep(0,n))
  z = .C("add", x=as.double(x), y=as.double(y), n=as.integer(n),
         out=as.double(out))
  z
}


Note 4: To return something with a name, you must set aside a variable
        with that name.  For example, the variable out is used for that
        purpose.  Make sure out is the right length.

Note 5: As we will see below, .C returns a list whose elements are all
        the arguments passed to the C function, modified in whatever
        way the C function modified them.

----------------------------------------------------------
STEP (5): Try it:

x = c(1,2,3)
y = c(4,5,6)
add.fun(x,y)



Splus output:
=============

$"x":
[1] 1 2 3

$"y":
[1] 4 5 6

$"n":
[1] 3

$out:
[1] 5 7 9



R output:
=========

$x
[1] 1 2 3

$y
[1] 4 5 6

&n
[1] 3

$out
[1] 5 7 9


----------------------------------------------------------
STEP (6): If you want to modify the source code you have to 

(a) unlink the old version from Splus or R:

    Splus: > dyn.close("add.so")
    R:     > dyn.unload("add.so")

(b) change the source code

(c) recompile and relink using the instructions above

----------------------------------------------------------

MORE HELP BY TYPING 

   Splus: > help(dyn.open)

   R:     > help(dyn.load)

AND FOLLOWING THE "RELATED TOPICS" FROM EITHER HELP PAGE.

----------------------------------------------------------