R: 指向C函数的指针

4
如何将指针从C代码传递到R中的函数(使用外部R),并在R中调用该函数?类似于:
C:
typedef void (* FunctionPtr)();
SEXP ans;
PROTECT(ans = /* ?some code? */);
R_tryEval(ans, R_GlobalEnv, NULL);
UNPROTECT(1);

R:

callback_function()

编辑: @Romain Francois的帖子非常有帮助。
我的应用程序代码:

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和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;
}

你说的话让我有些摸不着头脑。你只是想从R中调用一个C函数吗? - Dirk Eddelbuettel
我正在尝试将C(C ++)代码与R连接起来。我尝试了RInside,但在这种情况下不适用。我正在尝试将C回调传递给R,并从脚本中调用该函数(回调)。 - Andrii
也许你想看看 RcppDE,我在其中允许将任意的 C 函数从 R 传递到差分进化优化中。 - Dirk Eddelbuettel
3个回答

6

您需要的是外部指针。它们允许您封装对任意数据结构的指针。这里数据一词很重要,函数指针是另一种类型。如果您想使用C++Rcpp,我建议创建一个小类来封装函数指针:

typedef void (* FunctionPtr)();
class FunctionPointer {
  FunctionPtr ptr;
public:
    FunctionPointer( FunctionPtr ptr_) : ptr(ptr_){}
} ;

然后创建一个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() ;
}

在 R 中,您可以使用词法作用域来将外部指针封装到 R 函数中:

callback <- local( {
    ptr <- create_ptr()
    function(){
        invokeCallback( ptr )
        invisible(NULL)
    } 
} )
callback()

谢谢@Romain Francois,我今天会尝试并在这里发布结果。 - Andrii
你的回答非常接近我的问题,也许我的问题没有详细说明……我有一个可执行文件 myapp,它通过调用 Rf_initEmbeddedR(argc, argv) 和 Rf_endEmbeddedR(0) 来初始化和关闭 R。myapp 就像是 R 的包装器。我需要从 myapp 中传递一个函数指针(回调)到 R,并在脚本中调用此回调函数……你的示例展示了如何从外部源(如动态库)调用回调函数……我希望能够从 myapp 中调用在 R 范围内声明的函数并将 fun_ptr 作为其参数传递。谢谢! - Andrii
fun_ptr 应该是 myapp 的一部分。 - Andrii
我已经找到解决方案,今天稍后会发布。谢谢) - Andrii

4

另一种方法是使用Rcpp中的InternalFunction类:

#include <Rcpp.h>
using namespace Rcpp ;

void callback(){
    Rprintf( "hello from calback\n" ) ;    
}

// [[Rcpp::export]]
InternalFunction get_callback(){
    return InternalFunction(callback) ;    
}

这个实现与我在另一个答案中描述的类似。R端的事情由Rcpp处理:

callback <- get_callback()
callback()

0

首先导入库:

dyn.load("yourDLL.dll")

然后使用:

函数来调用已加载到R中的编译代码。

请参见R FFI

编辑:

首先编译您的C代码。在Windows上,可以执行以下操作,但在其他操作系统上类似:

gcc mylib.c -shared -o mylib.dll

然后在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

请注意,在C++中(而不是C),函数名必须是混淆名称

嗨,感谢您的回复。"我正在尝试将C(C ++)代码与R连接起来。我尝试了RInside,但在这种情况下不太适用。我正在尝试将C回调传递给R,并从脚本中调用该函数(回调)"(问题下的评论) - Andrii
如果您不想将C代码编译为DLL,则必须将R与您的C代码一起编译。 - Bernd Elkemann
1
答案有些值得怀疑(基本上是正确的,但没有用处),后续的评论是无意义的。 - Dirk Eddelbuettel
@eznme,请给我一个简单的例子,也许你的解决方案是正确的... 谢谢! - Andrii
@Andrii,你接受的答案有效吗?你试过我的代码了吗? - Bernd Elkemann
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接