我写了一个非常简单的R包,它返回R中整数值的指针:
R代码 Package 器:
getAddrss = function(expandMat)
{
result <- .C("pointer2", address = expandMat)
}
C++代码:
#include <cstdlib>
#include <R.h>
#include <string>
#include<iostream>
extern "C"
{
void pointer2(int* address)
{
std::cout<< "Memory Address: " << address <<std::endl;
std::cout<< "Value: " << address[0] <<std::endl;
}
}
但是,上述函数返回的内存地址与“lobstr”包中的“obj_addr”不同。
范例:
library(lobstr)
library(myRPackage)
x=3:5
> obj_addr(x)
[1] "0x7f0e416562a8"
> getAddrss(x)
Memory Address: 0x7f0e41655c98
Value: 3
1条答案
按热度按时间b0zn9rqh1#
您在这里使用
int*
。然而,Rinteger
向量不是Cint
(即使是长度为1的向量)。如R Internals中所述:R用户认为变量或对象是绑定到值的符号。这个值可以被认为是一个
SEXP
(一个指针),或者是它所指向的结构,一个SEXPREC
.[这是]一个C结构,包含如上所述的64位头部[和]三个指针(指向属性,前一个和下一个节点)。你可以在
lobstr
包中看到这一点:INTSXP
是24种可能的类型之一。参见R Internals了解其他SEXP
类型和包含的字段。要获取指向R对象的指针,而不是
int
,您需要接受SEXP
参数。这正是lobstr
所做的。obj_addr_()
(最终调用的函数)的C++源代码是:当这个函数被另一个C函数调用时,它可以返回
ss.str()
,这是一个Cstd::string
对象。然而,在我们的例子中,我们希望将内存地址作为字符向量返回给R:R字符向量存储为
STRSXP
s,一种类似VECSXP
的向量类型,其中每个元素都是CHARSXP
类型。您可以通过调用mkChar
并提供一个以null结尾的C样式字符串来获得CHARSXP
。从
std::string
创建R字符向量可以(通常应该)使用Rcpp::StringVector
非常简单地完成。然而,由于这抽象了创建SEXP
的一些值得展示的细节,我将在这里避免它,而是将我们的std::string
转换为char
数组并使用mkChar()
。我们可以使用
inline
R包来编译一些代码,它返回内存地址的一个元素字符向量:此函数返回与
lobstr::obj_addr()
相同的值:R的C接口阅读资源
我发现这些很有用:
1.威克姆的R Internals Github repo的vectors章节。
在最后一个链接中,威克姆说:
我不建议使用C编写新的高性能代码。用Rcpp写C++。Rcpp API保护您免受R API的许多历史特性的影响,为您负责内存管理,并提供许多有用的帮助方法。
这是在2014年写的。有趣的是,在2020年,
dplyr v1.0.0
发布了,更新日志指出:dplyr
删除了两个最重的依赖项:Rcpp
和BH
。这将使从源代码构建变得更加容易和快速。dplyr
开发者似乎已经接受了优化构建时间可能会有轻微的性能损失。这是here讨论。最终,我认为,了解R对象如何存在于C中是很重要的,但我的印象是,绝大多数包开发人员更喜欢Rcpp
的抽象,而不是直接处理R的C接口。