如何将.Call中的结构数组返回到R中的C共享库

时间:2012-01-04 00:18:34

标签: r

如何将struct数组从.Call返回到C共享库中的函数,然后在R中使用该数组?

例如:

typedef struct{
    int    thing1;
    int    thing2;
    float  thing3;
    float  thing4;
    char   thing5;
    //... many more things of various simple types
} MY_STRUCT;

SEXP R_Calls_Me(SEXP args) {

    // Do stuff with args...

    // Create arrayOfMyStructs as what type??

    return arrayOfMyStructs;
}

arrayOfMyStructs是什么类型,R可以使用它?

这似乎是一个人们想要做的常见事情,但我在编写R扩展的文档中找不到任何这样的例子。

2 个答案:

答案 0 :(得分:3)

通常,您使用要返回的组件创建列表(通用向量)。在你的情况下像

SEXP res = PROTECT(allocVector(VECSXP, 5));
SET_VECTOR_ELT(res, 0, ScalarInteger(a.thing1));
SET_VECTOR_ELT(res, 1, ScalarInteger(a.thing2));
SET_VECTOR_ELT(res, 2, ScalarReal(a.thing3));
...
UNPROTECT(1)
return res;

通常也会为矢量指定名称,例如:

const char *names[5] = { "thing1", "thing2", "thing3", "thing4", "thing5" };
SEXP sNames = PROTECT(allocVector(STRSXP, 5));
for (int i = 0; i < 5; i++) SET_STRING_ELT(res, i, mkString(names[i]));
setAttrib(res, R_NamesSymbol, sNames);
UNPROTECT(1);

请注意,您所描述的是不是数组而是结构。数组通常更容易作为向量传递。

答案 1 :(得分:2)

执行此操作最自然的方法可能是使用外部指针。您将返回指向R的指针,然后您的应用程序代码将操纵它。许多软件包现在都这样做,例如XML,h5r。

SEXP _h5R_make_ptr() {
    h5_holder* holder = (h5_holder*) Calloc(1, h5_holder);
    holder->id = 1;
    holder->is_file = 0;
    SEXP e_ptr = R_MakeExternalPtr(holder, R_NilValue, R_NilValue); 
    PROTECT(e_ptr);
    R_RegisterCFinalizerEx(e_ptr, h5R_finalizer, TRUE);
    UNPROTECT(1); 
    return e_ptr;
}