Back

Splus to C Interfacing

This is deprecated: please go to one of the links below, open the programmers guide, and read the chapter on interfacing C with S.

Splus Guides and Release Notes:     Unix/Linux     Windows


/* Example C program that is called from Splus and uses an Splus
   function via "call_S()".  

   H. Seltman 7/28/95

   This C function, r02tst() calculates the average, min and max of "n"
   random n(0,2) numbers.  The numbers are generated in a call from C
   back to S-plus to use rnorm().

   Compile this program with "cc -c -Aa +Z callc.c" 
   where callc.c is this file.  (Note -Ae is very similar to -Aa.)
   The +Z option is VERY important.

   From Splus, use:
     
     # Load C program into S-plus
     dyn.load2("callc.o")
     
     # The C program needs the address of the S function rnorm()
     fl_list(rnorm)
     # The easiest approach is to preallocate space for arguments to
     #   be returned by the C function.
     avg_as.double(0)
     rng_as.double(rep(0,2))
     
     # make the call to C with "n=5".
     rslt_.C("r02tst",fl,mean=avg,range=rng,count=as.integer(5))
     # note: C can't find array lengths, hence count is needed

     # report results
     cat("Mean=", round(rslt$mean,3), " N=",rslt$count, "\n", sep="")
     cat("Range=", round(rslt$range[1],3), " to ", 
       round(rslt$range[2],3), "\n", sep="")


   As required, the results of the call to C are returned to Splus as
   components of the value list of the ".C" call.  In this case the 
   average is returned in "avg", and the range is in a length-2 vector 
   called "rng".  These variables are included in the call to reserve 
   places for the results.

   From inside the C function r02tst, we use "call_S()" to make the S call
   "rnorm(n, 0.0, 2.0)".  This is a bit complicated because
   the arguments to the Splus function that is called by C (n, 1.0 and 2.0 here)
   can be of any type (integer, double, etc.) and can be atomic, vector
   (or matrix).   The same "richness" applies to the returned value(s) of the
   Splus function.  This example show how to handle some of these problems.

   Passing the function pointers from S to C must be done with "list(fn)".
   Although somewhat awkward, it does have the advantage
   that multiple function pointers could be passed in one argument, if
   the C function needs to call more than one S function.
*/

#include <stdlib.h>    /* note that e.g. printf() can be used */
#include <stdio.h>

/* Splus's rnorm() function has 3 arguments and 1 (vector) result */
#define NUM_ARGS 3
#define NUM_RSLTS 1

/* Non-varying declaration of call_S*/
extern void call_S(char *func, long nargs, char **arguments, 
  char **modes, long *lengths, char **names, long nres,
  char **results);




void r02tst(void **pLogFun, double *dAvg, double *dRng, long *lCnt) {
  char *arguments[NUM_ARGS];    /*arguments to rnorm()*/
  long lRndCnt=*lCnt;
  double dMean=0.0;
  double dSd=2.0;

  /* rnorm() needs n,mean,sd */
  char *modes[NUM_ARGS]={"integer","double","double"};

  /* arguments passed to rnorm() are atomic */
  long lengths[NUM_ARGS]={1L,1L,1L};

  /* I need to allocate space for pointers to the result(s) passed back from
     Splus.  For rnorm() the result is a single vector. The call_S fucntion will
     fill in addresses of the results which will point to some space it
     allocates. */
  char *results[NUM_RSLTS];    /* result pointers from rnorm() go here */

  double *dPtr,dTmp,dMin,dMax,dSum=0.0;
  int i;

  /* Assign arguments to rnorm() */
  arguments[0]=(char *) (&lRndCnt);
  arguments[1]=(char *) (&dMean);
  arguments[2]=(char *) (&dSd);

  /* Make the call back to rnorm() in Splus */
  call_S(pLogFun[0], (long)NUM_ARGS, arguments, modes, lengths, 
    NULL, (long)NUM_RSLTS, results);

  /* Manipulate the results */
  dPtr=(double *)results[0];  /* dPtr[] is the vector of n random numbers */
  dMin=dPtr[0]; 
  dMax=dMin;
  for (i=0; i<lRndCnt; i++) {
    dTmp=dPtr[i];
    printf("%d=%lf\n",i+1,dTmp);
    if (dTmp<dMin) dMin=dTmp;
    if (dTmp>dMax) dMax=dTmp;
    dSum=dSum+dTmp;
  }

  /* Pass results back to S */
  *dAvg=dSum/lRndCnt;
  *dRng=dMin;
  *(dRng+1)=dMax;

  return;
}

Notes:
UMN example (Geyer) pdf file from MathSoft
References: R.A. Becker, J.M. Chambers and A.R. Wilks (1988), "The New S Language," Chapman and Hall, London. This book is often called the "Blue book".

R. A. Becker and J. M. Chambers (1985), "Extending the S System," Chapman and Hall, London.

Back to my Home Page