call_S(func, nargs, arguments, modes, lengths, names, nres, results) char *func; char **arguments, **modes, **names, **results; long nargs, *lengths, nres;
amp;.C("my_c_code",list(myfun),as.double(xx), as.integer(length(xx))) The C code in my_c_code before the call to call_S should just pass this pointer around, not doing anything with it that might alter it.
Note that the calling routine is responsible for allocating space for all the arrays passed to call_S.
See section 7.2.4 of Becker, Chambers and Wilks for another example.
rev.test <- function(fun, vec) { # this S-PLUS function uses .C to pass an S-PLUS function and vector to a C routine. # The C routine can then use call_S to pass the vector on to the # user-supplied S-PLUS function. # z <- .C("rev_test0", list(fun), as.double(vec), as.integer(length(vec))) z[[2]] }rev.fun <- function(x, count) { # (any function of x here) x <- 2 * x + 1
# returns a list, which is what call_S expects when you tell it # you want more than one return value. The as.integer() around # count is important; the C code wants an S-PLUS integer not an S-PLUS double. return(list(x, as.integer(count))) }
/* C code for call_S example */ #include <stdio.h> /* (use this definition if your C compiler doesn't like the ANSI void declaration) */ #define void char
/* This C routine can be called using .C. It could do some calculations on the double array our_doubles, then could pass our_doubles on to the user-supplied S-PLUS function for more processing. */
void rev_test0(S_func, our_doubles, our_doubles_n) void **S_func; /* an S-PLUS list as received from .C */ double *our_doubles; /* an S-PLUS double */ long *our_doubles_n; /* an S-PLUS integer */ { long rev_test(), result;
/* (could do things with our_doubles array here) */
result = rev_test(S_func[0], our_doubles, our_doubles_n); }
/* a C routine that gets S-PLUS to call a function that expects a "double" vector and returns a "double" vector, together with its "integer" length. The routine then replaces x with the return value (which should be no longer than x) and returns the new length of x. */
long rev_test(S_func, x, nx) void *S_func; double *x; long *nx; { long lengths[2], count, i; char *arguments[2], *values[2]; char *modes[2], *names[2]; double *xnew;
/* here's the vector to be used as input to the S-PLUS function */ arguments[0] = (char *) x; modes[0] = "double"; lengths[0] = *nx; names[0] = "x";
/* here's the count, which is not really needed in this example */ arguments[1] = (char *) nx; modes[1] = "integer"; lengths[1] = 1; names[1] = NULL;
/* call the S-PLUS function, results in values array */ call_S(S_func, 2L, arguments, modes, lengths, names, 2L, values);
/* new vector, count (count isn't really used in this example) */ xnew = (double *) values[0]; count = *((long *) values[1]);
/* replace input vector with return vector from the S-PLUS function */ for (i = 0; i<count; i++) { *x++ = *xnew++; }
return count; }
rev.test(rev.fun,1:10) [1] 3 5 7 9 11 13 15 17 19 21