是否可以在附加的C代码中从现有的R包中调用C(或C)函数?
例如,我的包rje中的函数marginTable()使用相同名称的C函数.我想创建一个包含更多C代码的新包,其中一些可以使用marginTable()的C版本.我可以在新的C代码中调用该函数,而不仅仅是将C代码复制到新文件和包中吗?
或者使用这样的内部代码是不好的做法?
解决方法
所述R_RegisterCCallable / R_GetCCallable溶液指向@BrodieG可能比下面的一个更好,至少当一个可以修改其中需要登记的包,并且其中的函数调用的选择是直接的(下面的例子中从多个 – 来或者更复杂的R代码,它选择几个函数之一传递给C,就像lapply的FUN参数一样,函数的选择在R中比C更容易实现.当想要公开/访问许多功能时,相关的是
Linking to other packages.
相关的可能性是使用R_init_rje.c中的类似内容在rje包中注册C函数
#include <Rinternals.h> #include <R_ext/Rdynload.h> SEXP rje(SEXP who) { Rprintf("Hello %s\n",CHAR(STRING_ELT(who,0))); return R_NilValue; } static const R_CallMethodDef callMethods[] = { {".rje",(DL_FUNC) &rje,1},{NULL,NULL,0} }; void R_init_rje(DllInfo * info) { R_registerRoutines(info,callMethods,NULL); }
在NAMESPACE
useDynLib(rje,.registration=TRUE)
然后,在R as中可以获得C级入口点的地址
rje_c = getNativeSymbolInfo(".rje",PACKAGE="rje")
并且可以在其他包中使用它作为C函数的参数,例如,
.Call(.use_rje,rje_c$address,"A User")
同
#include <Rinternals.h> #include <R_ext/Rdynload.h> /* convenience definition of the function template */ typedef SEXP RJE_C_FUN(SEXP who); SEXP use_rje(SEXP rje_c_fun,SEXP who) { /* retrieve the function pointer,using an appropriate cast */ RJE_C_FUN *fun = (RJE_C_FUN *) R_ExternalPtrAddr(rje_c_fun); return fun(who); }
在包中说明这一点太笨拙了,但原理由以下文件rje.c说明
#include <Rinternals.h> #include <R_ext/Rdynload.h> /* convenience definition of the function template */ typedef SEXP RJE_C_FUN(SEXP who); SEXP rje(SEXP who) { Rprintf("Hello '%s'\n",0))); return R_NilValue; } SEXP use_rje(SEXP rje_c_fun,using an appropriate cast */ RJE_C_FUN *fun = (RJE_C_FUN *) R_ExternalPtrAddr(rje_c_fun); return fun(who); } static const R_CallMethodDef callMethods[] = { {".rje",{".use_rje",(DL_FUNC) &use_rje,2},NULL); }
使用R CMD SHLIB rje.c编译,并使用as
> dyn.load("rje.so") > .Call(".use_rje",getNativeSymbolInfo("rje")$address,"A User") Hello 'A User' NULL