首先,这真的有可能吗?可以调用同一个R包中的C脚本和C++脚本吗?
是的。 Rcpp 非常有名地利用了 R 的 C API。 (参考Section 1.6.4 Portable C and C++ code 的Writing R Extensions
。
如果前一种是可能的,那么如何在 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++ 文件中使用 extern 合并 C 代码,以使 C++ 中的函数名称与 C 联动。此外,我们将数据类型从SEXP 操作为NumericVector。
#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;
}