Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to construct a named list (a SEXP) to be returned from the C function called with .Call()?

Tags:

c

r

s-expression

I call C code via .Call("foo", <args>), where foo calls other C functions, computes the result and returns it. The result is a list of length 3 and I would like to name this list. To this end, foo does this:

/* Construct result list from variables containing the results */
SEXP res = PROTECT(allocVector(VECSXP, 3)); /* list of length 3 */
SET_VECTOR_ELT(res, 0, ScalarReal(a)); /* numeric(1) */ 
SET_VECTOR_ELT(res, 1, somenumericvector); /* numeric(<some length>) */
SET_VECTOR_ELT(res, 2, ScalarInteger(i)); /* integer(1) */

/* Name components and return */
SEXP nms = PROTECT(allocVector(STRSXP, 3)); /* names as SEXP */
char *nms_ = CHAR(STRING_ELT(nms, 0)); /* pointer to names */
char *names[3] = {"result_numeric", "result_numeric_vector", "result_integer"};
for(i = 0; i < 3; i++) nms_[i] = names[i]; 
setAttrib(res, R_NamesSymbol, nms);
UNPROTECT(1); 
return res;

Is this a/the correct way of constructing a named list of length 3?

The C function indeed returns back to R but once I assign the output to a variable in R, I immediately get a segmentation fault. What might be wrong? I can put 'debug statement's' (simple printf("...\n") right before the above 'return res;' and they are executed fine. Is there any convenient way to debug C code called from R?

like image 764
Marius Hofert Avatar asked May 16 '15 18:05

Marius Hofert


1 Answers

An alternative to BrodieG's answer is to use mkNamed from Rinlinedfuns.h (which contains an example of how to use mkNamed).

/* Construct named result list from variables containing the results */
const char *names[] = {"result_numeric", "result_numeric_vector",
    "result_integer", ""};                   /* note the null string */
SEXP res = PROTECT(mkNamed(VECSXP, names));  /* list of length 3 */
SET_VECTOR_ELT(res, 0, ScalarReal(a));       /* numeric(1) */ 
SET_VECTOR_ELT(res, 1, somenumericvector);   /* numeric(<some length>) */
SET_VECTOR_ELT(res, 2, ScalarInteger(i));    /* integer(1) */
UNPROTECT(1);
return res;
like image 134
Joshua Ulrich Avatar answered Oct 20 '22 15:10

Joshua Ulrich