2015-07-01 15 views
2

所以我从C++调用了一些R代码,并且我直接调用了R.dll(我知道关于Rcpp的知识,办公桌,但我不能用它来做这件事)。我有一个R脚本来设置一个变量,我想访问该变量的内容。在C++中嵌入R:访问VECSXP的元素

变量是字符串列表;在C++中,当我做TYPEOF(my_sexp)时,我得到VECSXP;到现在为止还挺好。现在我想将该列表的内容读入std :: vector。我曾尝试以下想法的许多排列:

SEXP vector_exp = VECTOR_ELT(my_sexp, 0); 
int element_count = TRUELENGTH(vector_exp); 
for (int i = 0 ; i < element_count ; i++) { 
    SEXP elem_sexp = VECTOR_ELT(my_sexp, i); 
    std::string element_string = R_CHAR(elem_sexp); 
} 

我的问题: - 使用TRUELENGTH,我可以访问冲突。使用长度,我得到一个错误的价值。 - 使用VECTOR_ELT()访问列表元素会导致访问冲突。 - 我已经尝试根据R头文件中的结构定义手动检查my_sexp的内存布局,但我似乎无法获得铸件权利以从中获得有意义的值。

那么,有没有人可以粗略地告诉我如何访问列表中的元素;或者指点我一个例子;或者将我指向Rcpp中这样的转换所在的位置?我试图自己找到最后一点,但没有得到太多 - 看起来像Rcpp的wrap()以某种方式“神奇地”处理它(通常)。

在此先感谢。

+3

出于好奇,为什么你不能使用Rcpp? – cdeterman

+0

或者,更明显的是,[RInside](http://dirk.eddelbuettel.com/code/rinside.html) - 当然会使用[Rcpp](http://dirk.eddelbuettel。com/code/rcpp.html) –

+0

我正在使用Visual Studio,并且我不希望代理之间的整体构建将包含第二个工具链。 – Roel

回答

2

我没有花太多时间为R的C接口的工作,因为我平时坚持RCPP,但以下似乎工作:

#include <Rcpp.h> 

// [[Rcpp::export]] 
void print_list_as_vector(SEXP lst) { 
    PROTECT(lst); 
    R_xlen_t n_list = XLENGTH(lst); 
    R_xlen_t n_elem = 0; 

    for (R_xlen_t i = 0; i < n_list; i++) { 
    n_elem += XLENGTH(VECTOR_ELT(lst, i)); 
    } 

    std::vector<std::string> vs; 
    vs.reserve(n_elem); 
    for (R_xlen_t i = 0; i < n_list; i++) { 
    R_xlen_t nj = XLENGTH(VECTOR_ELT(lst, i)); 
    for (R_xlen_t j = 0; j < nj; j++) { 
     vs.push_back(CHAR(STRING_ELT(VECTOR_ELT(lst, i), j))); 
    } 
    } 

    for (std::size_t i = 0; i < vs.size(); i++) { 
    Rcpp::Rcout << 
     vs[i] << std::endl; 
    } 

    UNPROTECT(1); 
} 

/*** R 

clist <- list(c("a", "b", "c"), c("l", "m", "n", "o", "p"), c("xyz1", "xyz2")) 

print_list_as_vector(clist) 
#a 
#b 
#c 
#l 
#m 
#n 
#o 
#p 
#xyz1 
#xyz2 

unlist(clist) 
# [1] "a" "b" "c" "l" "m" "n" "o" "p" "xyz1" "xyz2" 
*/ 

这是R内部测试/使用RCPP属性,你可以看到,但在代码的实际代码中,我试图坚持C接口来复制你的情况。

但解决您的问题(尽我所能) -

  1. 我一直使用XLENGTH获得的SEXP S上的长度,但我真的不能XLENGTHLENGTH之间说话的差异和TRUELENGTH,第一种方法似乎总能产生预期的结果。
  2. 我使用VECTOR_ELT(lst, i)来访问VECSXPlst中的第i个元素。
  3. 考虑到数据/函数的上下文,我知道VECTOR_ELT(lst, i)正在返回一个STRSXP - 即一个字符向量。这个STRSXP的第j个元素用STRING_ELT(..., j)访问,并且由于这返回CHARSXP,所以我们用CHAR来包装它以获得const char*,它被添加到std::vector<std::string>

遗憾的是,似乎没有要对R公司的C内部多文档,但哈德利有一个有用reference page here,如果一切都失败了,你可以通过the source itself挖。

+1

谢谢,这一直很有帮助。我只需要弄清楚你提到的各种长度函数之间的区别是什么,因为直到现在我已经使用了Rf_length(),并且这似乎也起作用了。无论哪种方式,事实证明,我的真正问题是,我的名单中没有真正的CHARSXP,而是LANGSXP的;所以我必须做的是用capture.output将我的R脚本中的变量分配给它:result < - capture.output(summary(fit))(其中'fit'是glm()的结果)。 – Roel