繁体   English   中英

为什么用.Call 而不是.C 调用我的C++ function 时会出现段错误?

[英]Why do I get a segfault when calling my C++ function with .Call rather than .C?

我的最终目标是从 R 中调用一些 C++ 函数,这是我遇到障碍的 MNWE。 如果我正确读取房间,当我用.Call调用我的 function 但当我用.C调用它时,我似乎遇到了段错误。

这是我的短 C++ function

// test.cpp
#include <iostream>

extern "C" void fnTest() {
  std::cout << "Hello" << std::endl;
}

然后我用它编译

R CMD SHLIB -o test.so test.cpp

其中给出了以下 output:

g++ -std=gnu++11 -shared -L/usr/lib64/R/lib -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -o te
st.so test.o -L/usr/lib64/R/lib -lR

现在在 R 我做了

> dyn.load("test.so")
> .C("fnTest")
Hello
list()
> .Call("fnTest")
Hello

 *** caught segfault ***
address 0x30, cause 'memory not mapped'

Possible actions:
1: abort (with core dump, if enabled)
2: normal R exit
3: exit R without saving workspace
4: exit R saving workspace
Selection:

我为这两个函数阅读的文档在这里,似乎并没有表明这两个函数的调用格式有很大差异。 我尝试了其他几种变体(例如,我能够成功地将 arguments 传递给.C但不是.Call )并且没有任何成功。

从 R 中调用.Call function 的正确方法是什么?

除了这个最小的例子之外,关于我的最终用例的一些注释,希望这不是一个XY 问题:我有一个具有许多复杂依赖项的项目,我知道如何使用 CMake 但不是直接从 g++ 构建。 我能够从这个项目构建一个共享库,然后我可以链接到一个“R 兼容”共享库( R CMD SHLIB -o test.so test.cpp -L/path/to/my/lib/ -l my_lib_name ) 我能够将dyn.load()到我的 R 环境中。 那时我遇到了上述.C.Call问题。

通过阅读一些额外的文档(我应该在第一遍中找到),我相信你不能。调用返回类型为void.Call 我找不到明确提及这一点,但文档中没有示例(例如this section )列出了SEXP以外的返回类型,并且文档中有一次声明:

您将处理的所有 R 对象都将使用 SEXP 类型处理

On the other hand, as documented in the Interface functions.C and.Fortran section , any function that you .C must have a return type of void:

请注意,编译后的代码不应返回任何内容,除非通过其 arguments:C 函数应为 void 类型,Fortran 子程序应为子例程。

以下是一些可以在 OP 中编译的示例。 .Call函数似乎没有默认的“null”返回类型,但allocVector(REALSXP, 0) R_NilValue似乎运行良好。

// test.cpp

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

extern "C" void fnPrintC() {
  Rprintf("Hello world!\n");
}

extern "C" SEXP fnPrintCall() {
  Rprintf("Hello world!\n");

  // return allocVector(REALSXP, 0);
  return R_NilValue;
}

extern "C" SEXP fnAddCall(SEXP a, SEXP b) {
  double* xa = REAL(a);
  double* xb = REAL(b);

  SEXP ans = allocVector(REALSXP, 2);
  REAL(ans)[0] = *xa + *xb;
  REAL(ans)[1] = *xa - *xb;

  return ans;
} 

在这里,它们被称为 R。 请注意,如果我们不想看到它,我们可以将 ( void ) output 发送到虚拟变量x

> dyn.load("test.so")

> x <- .C("fnPrintC")
> Hello world!

> x <- .Call("fnPrintCall")
> Hello world!

> .Call("fnAddCall", 4, 3)
> [1] 7 1

一般来说,上面链接的文档很有帮助,我建议任何有类似问题的人从那里开始,我当然希望我能早点更彻底地阅读它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM