首页 > 解决方案 > 带有 .c 和 .cpp 文件的 R 包,带有 Rcpp

问题描述

我正在尝试使用 Rcpp 包作为依赖项构建一个 R 包,其中包含 C(以 .c 文件的形式)和 C++ 代码(以 .cpp 文件的形式)。

我有一些问题。

  1. 首先,真的有可能做到这一点吗?可以调用同一个 R 包中的 C 脚本和 C++ 脚本吗?
  2. 如果前一个是可能的,那么如何在 C 和 C++ 脚本中正确注册函数。

为了解决这个问题,我在我的 GitHub 页面 ( https://github.com/tpbilton/testrcpp ) 上设置了一个小示例。我曾经Rcpp.package.skeleton("testrcpp")初始化包并添加了一些功能(来自本教程https://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-introduction.pdf),然后运行Rcpp::compileAttributes()​​. 我安装了软件包,c++ 函数convolve_cpp工作正常,但convolve_c没有注册,我不知道如何正确执行此操作,我尝试注册这两个函数的尝试无济于事。

标签: crcppr-package

解决方案


首先,真的有可能做到这一点吗?可以调用同一个 R 包中的 C 脚本和 C++ 脚本吗?

是的。Rcpp非常有名地利用了RC API。(参见编写 R 扩展 第 1.6.4 节可移植 C 和 C++ 代码

如果前一个是可能的,那么如何在 C 和 C++ 脚本中正确注册函数。

理想情况下,只有C++脚本的表面方面。否则,你会被卡住写胶水。

我采用了这种方法。这篇文章继续详细介绍了细微的变化。可以在非现场找到一个工作示例:

https://github.com/r-pkg-examples/rcpp-and-c


简而言之,我们将为函数定义创建一个头文件并将其包含在C代码中。从那里,我们将创建第三个C++文件,并使用 _Rcpp将该函数导出到R中。

convolve_in_c.h

在这里,我们使用包含保护,#ifndef#define确保如果我们多次重用头文件,函数定义不会重复。

#ifndef CONVOLVE_C_H
#define CONVOLVE_C_H

SEXP convolve_c(SEXP a, SEXP b);

#endif /* CONVOLVE_C_H */

convolve_in_c.c

现在,让我们修改文件以允许我们的自定义标题。

#include <R.h>
#include <Rinternals.h>

// Incorporate our header
#include "convolve_in_c.h"

SEXP convolve_c(SEXP a, SEXP b) {
  int na, nb, nab;
  double *xa, *xb, *xab;
  SEXP ab;
  a = PROTECT(coerceVector(a, REALSXP));
  b = PROTECT(coerceVector(b, REALSXP));
  na = length(a); nb = length(b);
  nab = na + nb - 1;
  ab = PROTECT(allocVector(REALSXP, nab));
  xa = REAL(a); xb = REAL(b); xab = REAL(ab);
  for(int i = 0; i < nab; i++)
    xab[i] = 0.0;
  for(int i = 0; i < na; i++)
    for(int j = 0; j < nb; j++)
      xab[i + j] += xa[i] * xb[j];
  UNPROTECT(3);
  return ab;
}

convolve_from_c_to_rcpp.cpp

最后,我们在C++文件中使用C代码,使 C ++中的函数名称与C链接保持一致。此外,我们将数据类型从 操作到。externSEXPNumericVector

#include "Rcpp.h"

// Define the method signature

#ifdef __cplusplus
extern "C" {
#endif

#include "convolve_in_c.h"

#ifdef __cplusplus
}
#endif

//' Call C function from Rcpp
//' 
//' Uses the convolve_c function inside of a C++ routine by Rcpp.
//' 
//' @param a,b A `numeric` vector.
//' 
//' @return 
//' A `numeric` vector of length \eqn{N_a + N_b}.
//' 
//' @examples
//' 
//' convolve_from_c(1:5, 5:1)
//' 
//' @export
// [[Rcpp::export]]
Rcpp::NumericVector convolve_from_c(const Rcpp::NumericVector& a,
                                    const Rcpp::NumericVector& b) {

  // Compute the result in _C_ from _C++_.
  SEXP ab = convolve_c(a, b);

  // Cast as an _Rcpp_ NumericVector 
  Rcpp::NumericVector result( ab );

  // Alternatively:
  // Rcpp::NumericVector result( convolve_c(a, b) );

  // Return result
  return result;
}

推荐阅读