如何将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扩展的文档中找不到任何这样的例子。
答案 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;
}