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: ----------------------------------------------------------------------------- e...@max:~$ r /tmp/andrew.R Loading required package: methods [1] 0 [1] 1.5 5.0 3.5 [1] 1 2 9 e...@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 | e...@debian.org | http://dirk.eddelbuettel.com ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel