8

我通过调用 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;

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

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

4

3 回答 3

10

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;
于 2015-05-16T19:53:22.150 回答
5

由于您要求使用普通的香草方式,因此您需要使用mkChar和从 C 字符串创建一个 R 字符向量SET_STRING_ELT

for(i = 0; i < 3; i++) SET_STRING_ELT(nms, i, mkChar(names[i]));  

现在,您正在尝试将原始 C 字符串用作 R 对象,但这是行不通的。

Re:debugging,你可以PrintValue在 C 代码中使用来打印出 R 对象。

综上所述,除非你有非常具体的理由想要纯香草,否则你应该考虑Rcpp

于 2015-05-16T18:24:00.273 回答
3

根据@nrussell 的好建议,一个语句中的解决方案(为了易读性分成四行)

R> cppFunction('List marius(double a, NumericVector b, int c) \
       { return List::create(Named("resnum")=a,\ 
                             Named("resvec")=b, \
                             Named("resint")=c); }')
R> marius(1.2, sqrt(3:5), 42L)
$resnum
[1] 1.2

$resvec
[1] 1.73205 2.00000 2.23607

$resint
[1] 42

R> 
于 2015-05-16T18:18:27.347 回答