call_S(func, nargs, arguments, modes, lengths, names, nres, results) char *func; char **arguments, **modes, **names, **results; long nargs, *lengths, nres;
.C
call; e.g.,
myfun <- function(x) {x+1}
.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.
char *
when put into
arguments
:
double *xarg;
...
arguments[0] = (char *)xarg;
names
can be
0
, as can any of
names[i]
.
If
names
is not
0
and
names[i]
is not
0
, then
names[i]
is a
pointer to the character string in C to be used as the actual argument
name corresponding in the call to the S-PLUS function.
nres
is one and the function produces an atomic result (e.g., numeric),
this is passed back. Otherwise, the S-PLUS function is expected to produce
a list whose elements provide the results passed back.
If the actual number of results exceeds
nres
, the rest are ignored; if
it is less than
nres
, null pointers are returned in the corresponding
elements of
results
.
call_S
. The data may be of any mode, but will be
cast to
char *
by
call_S
. The calling routine will want to cast them
back to the desired type:
double *yresult;
...
yresult = (double *)results[0];
The S-PLUS function must assure the results
are the mode and length expected by the C code.
Note that the calling routine is responsible for allocating space for
all the arrays passed to
call_S
.
rev.test <- function(fun, vec) { # this S-PLUS function uses .C to pass a 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 a S-PLUS integer not a 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; /* a S-PLUS list as received from .C */ double *our_doubles; /* a S-PLUS double */ long *our_doubles_n; /* a 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