2014-10-31 141 views
2

我正在使用SWIG生成封装代码以从R语言访问C代码。包装代码使用R externalptr类型来保存对C指针的引用。在某些情况下,这些指针在C端为NULL,在R中显示时显示为零值。在R方面,在externalptr上拨打is.null()is.na()均返回FALSE。例如:如何检查externalptr是否为空R

> val = librdf_query_results_get_binding_value(results, 2) 
> val 
An object of class "_p_librdf_node_s" 
Slot "ref": 
<pointer: (nil)> 
> class([email protected]) 
[1] "externalptr" 
> is.null([email protected]) 
[1] FALSE 
> is.na([email protected]) 
[1] FALSE 

如可以从上面的代码输出中可以看出,狭槽ref含有externalptr,这是“无”。我如何从R中确定C中的这个指针是NULL?

如果你想在上下文中查看代码,它可在GitHub上: https://github.com/ropensci/redland-bindings/blob/master/R/redland/inst/tests/test.redland_base.R#L40

+4

我想你可能需要一个C/C++帮助函数来为你计算外部指针。 – 2014-10-31 02:30:41

+0

我认为@DirkEddelbuettel是对的。您可能需要考虑'bigmemory :: is.nil'作为指导。 – 2014-10-31 02:58:57

+0

谢谢@DirkEddelbuettel,我很怀疑。那么你认为''externalptr'类型的重写is.null()是否合理,还是将它放在我自己的包中会更好? – metamattj 2014-10-31 04:49:31

回答

3

为了完整起见,这里是我使用的解决方案。按照@DirkEddelbuettel的建议,它需要C端的一个功能,以及一个R端的功能。 C函数是:

#include <Rinternals.h> 

SEXP isnull(SEXP pointer) { 
    return ScalarLogical(!R_ExternalPtrAddr(pointer)); 
} 

而在R中的包装函数是:

is.null.externalptr <- function(pointer) { 
    stopifnot(is(pointer, "externalptr")) 
    .Call("isnull", pointer) 
} 

对于使用的一个例子来自R内:

> p <- new("externalptr") 
> p 
<pointer: (nil)> 
> is.null.externalptr(p) 
[1] TRUE 
3

C溶液上方是最优雅,但编译器可能并不总是可用的。不需要编译代码的一个解决办法是这样的:

identical(pointer, new("externalptr")) 

但是这不会如果对象具有自定义属性的工作。如果是这样的话,你可以这样做:

isnull <- function(pointer){ 
    a <- attributes(pointer) 
    attributes(pointer) <- NULL 
    out <- identical(pointer, new("externalptr")) 
    attributes(pointer) <- a 
    return(out) 
} 

又有点比C解决方案更多地参与,但将在一个简单的脚本运行在任何平台上。