我调用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代码?
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)
由于你要求普通的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.