在C中从R包调用C代码
是否可以在附加的C代码中从现有的R包调用C(或C++)函数 例如,我的包在C中从R包调用C代码,c,r,C,R,是否可以在附加的C代码中从现有的R包调用C(或C++)函数 例如,我的包rje中的函数marginTable()使用同名的C函数。我想创建一个包含更多C代码的新包,其中一些代码可以使用C版本的marginTable()。除了将C代码复制到新的文件和包中,我可以从新的C代码中调用该函数吗 还是像这样使用内部代码只是一种不好的做法 [很多人都问过如何从另一个R包调用编译后的代码,但都想在R中调用,而不是用C代码。由@BrodieG提出的R\u registerCallable/R\u GetCCal
rje
中的函数marginTable()
使用同名的C函数。我想创建一个包含更多C代码的新包,其中一些代码可以使用C版本的marginTable()
。除了将C代码复制到新的文件和包中,我可以从新的C代码中调用该函数吗
还是像这样使用内部代码只是一种不好的做法
[很多人都问过如何从另一个R包调用编译后的代码,但都想在R中调用,而不是用C代码。由@BrodieG提出的
R\u registerCallable
/R\u GetCCallable
解决方案可能比下面的解决方案更好,至少可以在需要注册且调用函数的选择是直接的情况下修改包(下面的示例来自于或多或少复杂的R代码,该代码选择几个函数中的一个传递给C,很像Lappy的有趣参数,其中函数的选择在R中比在C中更容易实现)。当想要公开/访问许多函数时,这也是相关的
一种相关的可能性是在rje包中注册您的C函数,使用类似于在R\u init\u 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, NULL, callMethods, NULL, NULL);
}
#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", CHAR(STRING_ELT(who, 0)));
return R_NilValue;
}
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);
}
static const R_CallMethodDef callMethods[] = {
{".rje", (DL_FUNC) &rje, 1},
{".use_rje", (DL_FUNC) &use_rje, 2},
{NULL, NULL, 0}
};
void R_init_rje(DllInfo * info)
{
R_registerRoutines(info, NULL, callMethods, NULL, NULL);
}
C级入口点的地址在R中可用
rje_c = getNativeSymbolInfo(".rje", PACKAGE="rje")
并且可以通过将其用作C函数的参数,在其他程序包中使用,例如
.Call(.use_rje, rje_c$address, "A User")
与
使用R CMD SHLIB rje.c
编译,并用作
> dyn.load("rje.so")
> .Call(".use_rje", getNativeSymbolInfo("rje")$address, "A User")
Hello 'A User'
NULL
是的,这是可能的,是的,有一些简单的例子 例如,参见我们的(最近的ish) 包裹 它提供了
serialize()
,供其他CRAN软件包(如我们的
包裹
其他软件包也可以做到这一点:
- 使用C 代码来自 ; 李>
- 使用来自的代码 ; 及
- 这是我用的
R_init_rje
中R_registercallable
的调用(@MartinMorgan示例第一块中的最后一个函数)。免责声明:我还没有试过这个。
#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", CHAR(STRING_ELT(who, 0)));
return R_NilValue;
}
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);
}
static const R_CallMethodDef callMethods[] = {
{".rje", (DL_FUNC) &rje, 1},
{".use_rje", (DL_FUNC) &use_rje, 2},
{NULL, NULL, 0}
};
void R_init_rje(DllInfo * info)
{
R_registerRoutines(info, NULL, callMethods, NULL, NULL);
}
> dyn.load("rje.so")
> .Call(".use_rje", getNativeSymbolInfo("rje")$address, "A User")
Hello 'A User'
NULL