问题
How to pass a pointer to a function from C code to R (using External R) and after call that function from R??
Something like:
C:
typedef void (* FunctionPtr)();
SEXP ans;
PROTECT(ans = /* ?some code? */);
R_tryEval(ans, R_GlobalEnv, NULL);
UNPROTECT(1);
R:
callback_function()
EDIT:
@Romain Francois's post was very helpful.
myapp code:
namespace
{
void callback()
{
std::cout << "callback\n" << std::flush;
}
}
class Worker
{
public:
/*...*/
void initialize(argc, argv)
{
Rf_initEmbeddedR(argc, argv);
SEXP ans, val;
typedef void (* FunctionPtr)();
PROTECT(ans = Rf_lang2(Rf_install("source"), Rf_mkString("script.R")));
R_tryEval(ans, R_GlobalEnv, NULL);
UNPROTECT(1);
PROTECT(val = Rf_ScalarInteger((int)(&callback)));
/* pass the address of the pointer to a function */
PROTECT(ans = Rf_lang2(Rf_install("setCallback"), val));
R_tryEval(ans, R_GlobalEnv, NULL);
UNPROTECT(2);
}
void uninitialize()
{
Rf_endEmbeddedR(0);
}
};
R and Rcpp
script.R
###################
sourceCpp("utils.cpp")
###################
callback <- function()
{
callCallback()
}
utils.cpp
#include <Rcpp.h>
using namespace Rcpp;
typedef void (* Callback)();
static Callback spCallback = 0;
// [[Rcpp::export]]
void callCallback()
{
if (spCallback) {
spCallback();
} else {
Rprintf("ERROR: callback is not set");
}
}
// [[Rcpp::export]]
void setCallback(const int address)
{
spPlaceOrder = (Callback)address;
}
回答1:
External pointers are what you are looking for. They ley you encapsulate pointers to arbitrary data strucures. The word data is important here and function pointers are a different beast. If you want to use C++
and Rcpp
, what I would suggest is to create a small class that encapsulates the function pointer:
typedef void (* FunctionPtr)();
class FunctionPointer {
FunctionPtr ptr;
public:
FunctionPointer( FunctionPtr ptr_) : ptr(ptr_){}
} ;
and then create an XPtr<FunctionPointer>
:
#include <Rcpp.h>
using namespace Rcpp ;
// your callback function
void callback(){
Rprintf( "hello from callback\n" ) ;
}
// The function that creates an external pointer to your
// callback
// [[Rcpp::export]]
XPtr<FunctionPointer> create_ptr(){
return XPtr<FunctionPointer>( new FunctionPointer(callback) );
}
// The function that invokes the callback
// [[Rcpp::export]]
void invokeCallback( XPtr<FunctionPointer> callback){
callback->ptr() ;
}
On the R side, you can use lexical scoping for example to wrap the external pointer into an R function:
callback <- local( {
ptr <- create_ptr()
function(){
invokeCallback( ptr )
invisible(NULL)
}
} )
callback()
回答2:
Another way is to use the InternalFunction
class in Rcpp
:
#include <Rcpp.h>
using namespace Rcpp ;
void callback(){
Rprintf( "hello from calback\n" ) ;
}
// [[Rcpp::export]]
InternalFunction get_callback(){
return InternalFunction(callback) ;
}
The implementation is similar to what I described in the other answer. Things on the R side are taken care of by Rcpp
:
callback <- get_callback()
callback()
回答3:
First load the lib:
dyn.load("yourDLL.dll")
Then use:
Functions to make calls to compiled code that has been loaded into R.
See The R FFI
EDIT:
First compile your C-code. On Windows that is the following, but on other OS's similar:
gcc mylib.c -shared -o mylib.dll
and then in R:
dyn.load("mylib.dll")
tmp1 <- as.raw(rep(0,4)) # 4 bytes to be sent to the function's argument
tmp2<-.C("yourFunctionName", tmp1) # tmp2 now has the data returned by the func
Note that in c++ (not c) the function name has to be the mangled name
来源:https://stackoverflow.com/questions/13904786/r-pointer-to-c-function