[Rd] must .Call C functions return SEXP?

Dirk Eddelbuettel edd at debian.org
Thu Oct 28 02:19:51 CEST 2010


On 27 October 2010 at 19:43, Andrew Piskorski wrote:
| For using R's .Call interface to C functions, all the examples I've
| seen have the C function return type SEXP.  Why?  What does R actually
| do with this return type?  What happens if I *don't* return a SEXP?
| 
| Reason I ask, is I've written some R code which allocates two long
| lists, and then calls a C function with .Call.  My C code writes to
| those two pre-allocated lists, thus, I thought I should NOT need to
| return any SEXP from my C function.  However, if I do that, it
| segfaults somewhere in "src/main/memory.c".
| 
| If I instead return the SEXP for one of my two result lists it appears
| to work fine...  But of course I don't understand what's going on here
| and so don't trust it.  The list SEXP I am returning was allocated by
| R, not by my C code, so why does it make any difference whether my C
| function returns it or not?
| 
| >From "src/main/names.c" I see that .Call is implemented by do_dotcall
| in "src/main/dotcode.c".  I don't necessarily understand what that
| really does, but AFAICT if my C function returns nothing, the
| do_dotcall's retval should simply remain set to R_NilValue, which
| should be fine.
| 
| I must be misunderstanding something here, but I don't know what, and
| would definitely appreciate any help.  Thanks!
| 
| 
| My R code looks like this:
| 
|   result.1 <- vector("list" ,1e6)
|   result.2 <- vector("list" ,1e6)
|   .Call("my_C_function", result.1, result.2, other.input)
| 
| My C code looks like this:
| 
|   SEXP result_v; 
|   result_v = Rf_allocVector(REALSXP, 5); 
|   SET_VECTOR_ELT(result_list_1, k1, result_v); 
|   REAL(result_v)[0] = some_number; 
|   REAL(result_v)[1] = another_number; 
|   /* Also do the same sort of thing for result_list_2. */
|   return(result_list_1);  /* Appears to work ok. */
|   /* return; */  /* Segfaults. */


I don't deal with the C API when I can avoid it. Here is your setup in a
simple, self-contanined Rcpp example using inline:

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

library(inline)

# body of C++ function
src <- 'Rcpp::NumericVector vc = Rcpp::NumericVector(vr);
        Rcpp::IntegerVector wc = Rcpp::IntegerVector(wr);

        vc[1] = 2*vc[1];
        wc[2] = 3*wc[2];

        return Rcpp::wrap(0L);
        '

# create it
fun <- cxxfunction(signature(vr="numeric", wr="integer"), src, plugin="Rcpp")

vr <- seq(1.5, 3.5)
wr <- seq(1L,  3L)

# call it 
print(fun(vr, wr))
print(vr)
print(wr)

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

We create 'vr' and 'wr' at the R level, pass them to C++ where they are taken
as numeric and int vectors (with type checking and casts).   

Your hunch is correct -- SEXP pointer changes continue back to the R level.
We do return something (R_NilValue is an option too) as that is how .Call()
declared, pure and simple.

If I run this in my emacs shell buffer, I get this:

-----------------------------------------------------------------------------
edd at max:~$ r /tmp/andrew.R 
Loading required package: methods
[1] 0
[1] 1.5 5.0 3.5
[1] 1 2 9
edd at max:~$ 
-----------------------------------------------------------------------------

First the zero, then the two (changed) vectors even though I didn't
explicitly return them. So this does work -- but I don't like hidden side
effects.  Much better, in my book, to explicitly return as you'd do with

    return Rcpp::List::create(Rcpp::Named("newv"=vc,
                              Rcpp::Named("neww"=wc)));

which will get you a named list at the R level.

Feel free to come over to rcpp-devel is you have questions about the Rcpp and
inline parts.

Dirk

-- 
Dirk Eddelbuettel | edd at debian.org | http://dirk.eddelbuettel.com



More information about the R-devel mailing list