如何构造一个从使用.Call()调用的C函数返回的命名列表(SEXP)?

Mar*_*ert 5 c r s-expression

我调用C代码.Call("foo", <args>),其中foo调用其他C函数,计算结果并返回它.结果是长度为3的列表,我想列出这个列表.为此,foo做到了这一点:

/* 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;
Run Code Online (Sandbox Code Playgroud)

这是构建长度为3的命名列表的正确方法吗?

C函数确实返回R但是一旦我将输出分配给R中的变量,我立即得到分段错误.可能有什么问题?我可以把'debug statement''(简单地printf("...\n")放在上面'return res;'之前,它们执行得很好.有没有方便的方法来调试从R调用的C代码?

Jos*_*ich 8

BrodieG答案的替代方法是使用mkNamedRinlinedfuns.h(其中包含如何使用的示例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;
Run Code Online (Sandbox Code Playgroud)

  • 真棒,这应该是答案. (2认同)

Bro*_*ieG 5

由于你要求普通的vanilla方式,你需要使用mkChar和从C字符串创建一个R字符向量SET_STRING_ELT:

for(i = 0; i < 3; i++) SET_STRING_ELT(nms, i, mkChar(names[i]));  
Run Code Online (Sandbox Code Playgroud)

现在,您正在尝试将原始C字符串用作R对象,这将无法正常工作.

Re:调试,可以用PrintValueC代码打印出R对象.

所有这些都说,除非你有一个非常具体的理由想要普通香草,你应该考虑Rcpp.