Mar*_*gan 30
如上所述,想法是使用外部指针."写入R扩展"手册中对此进行了描述.这是一个简单的例子.
包括相关的R头
#include <Rdefines.h>
Run Code Online (Sandbox Code Playgroud)
我们将创建一个可以容纳长度最多为15的C char*的对象
const int N_MAX=15;
Run Code Online (Sandbox Code Playgroud)
当外部指针不再由任何R对象表示时,外部指针就像一个终结器.我们在这里安全地玩它,在释放之前检查指针地址是否有效(使用Free,因为我们将使用Calloc进行分配 - 这些是C级内存分配函数,这些函数在调用C时持续存在,与R_alloc不同)并清除指针表示它已经完成.
static void
_finalizer(SEXP ext)
{
if (NULL == R_ExternalPtrAddr(ext))
return;
Rprintf("finalizing\n");
char *ptr = (char *) R_ExternalPtrAddr(ext);
Free(ptr);
R_ClearExternalPtr(ext);
}
Run Code Online (Sandbox Code Playgroud)
这是我们的构造函数.它需要一些R'信息'它随身携带(在本例中稍后不再使用)然后为短字符串分配一些内存.我们用x和info构造一个外部指针(R_NilValue是一个'tag',按照惯例我们可以用来标记我们的对象 - mkString("MyCObject")或类似的).我们将终结器与外部指针相关联.PROTECT/UNPROTECT用于防止通过调用R_RegisterCFinalizerEx触发垃圾收集器.当R分配内存时,可以调用垃圾收集器; 很难知道这种情况何时发生(我们可以跟踪代码流),所以我们安全地播放它并在创建它时将外部指针添加到PROTECT.
SEXP
create(SEXP info)
{
char *x = Calloc(N_MAX, char);
snprintf(x, N_MAX, "my name is joe");
SEXP ext = PROTECT(R_MakeExternalPtr(x, R_NilValue, info));
R_RegisterCFinalizerEx(ext, _finalizer, TRUE);
UNPROTECT(1);
return ext;
}
Run Code Online (Sandbox Code Playgroud)
这是getter,只是引用外部指针地址并将其作为R字符返回(1)
SEXP
get(SEXP ext)
{
return mkString((char *) R_ExternalPtrAddr(ext));
}
Run Code Online (Sandbox Code Playgroud)
以及获取外部指针和字符(1)的setter,将str的第一个元素的C表示复制到我们的对象中.我们返回逻辑(1),但可以返回任何内容.
SEXP
set(SEXP ext, SEXP str)
{
char *x = (char *) R_ExternalPtrAddr(ext);
snprintf(x, N_MAX, CHAR(STRING_ELT(str, 0)));
return ScalarLogical(TRUE);
}
Run Code Online (Sandbox Code Playgroud)
如果这是在文件tmp.c中,我们编译
R CMD SHLIB tmp.c
Run Code Online (Sandbox Code Playgroud)
或者将其作为文件集成在一个包中src/tmp.c
并正常构建包.使用:
> dyn.load("tmp.so")
> x <- .Call("create", list("info could be any R object", 1:5))
> .Call("get", x)
[1] "my name is joe"
> ## reference semantics!
> .Call("set", x, "i am sam i am")
[1] TRUE
> .Call("get", x)
[1] "i am sam i am"
> x <- NULL
> gc()
finalizing
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 339306 18.2 467875 25 407500 21.8
Vcells 202064 1.6 786432 6 380515 3.0
Run Code Online (Sandbox Code Playgroud)
这是第二个示例,其中包含一个增加的int的结构.
#include <Rdefines.h>
struct Foo {
int x;
};
static void
_finalizer(SEXP ext)
{
struct Foo *ptr = (struct Foo*) R_ExternalPtrAddr(ext);
Free(ptr);
}
SEXP
create()
{
struct Foo *foo = Calloc(1, struct Foo);
foo->x = 0;
SEXP ext = PROTECT(R_MakeExternalPtr(foo, R_NilValue, R_NilValue));
R_RegisterCFinalizerEx(ext, _finalizer, TRUE);
UNPROTECT(1);
return ext;
}
SEXP
incr(SEXP ext)
{
struct Foo *foo = (struct Foo*) R_ExternalPtrAddr(ext);
foo->x += 1;
return ScalarInteger(foo->x);
}
Run Code Online (Sandbox Code Playgroud)