简体   繁体   English

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

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

My end goal is to call some C++ functions from within R, here is a MNWE of where I'm hitting a roadblock.我的最终目标是从 R 中调用一些 C++ 函数,这是我遇到障碍的 MNWE。 If I'm reading the room correctly, I seem to get a segfault when I call my function with .Call but when I call it with .C everything works fine.如果我正确读取房间,当我用.Call调用我的 function 但当我用.C调用它时,我似乎遇到了段错误。

Here is my short C++ function这是我的短 C++ function

// test.cpp
#include <iostream>

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

Which I then compiled with然后我用它编译

R CMD SHLIB -o test.so test.cpp

Which gave the following output:其中给出了以下 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

Now within R I did现在在 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:

The documentation that I read for these two functions is here and didn't seem to indicate much of a difference in the calling format of the two functions.我为这两个函数阅读的文档在这里,似乎并没有表明这两个函数的调用格式有很大差异。 I tried several other variations (eg I was was able to pass arguments successfully to .C but not .Call ) and didn't have any success.我尝试了其他几种变体(例如,我能够成功地将 arguments 传递给.C但不是.Call )并且没有任何成功。

What is the proper way to .Call a C++ function from within R?从 R 中调用.Call function 的正确方法是什么?

Some notes on my eventual use case beyond this minimal example, hopefully this is not an XY problem : I have a project with many complicated dependencies which I know how to build with CMake but not directly from g++.除了这个最小的例子之外,关于我的最终用例的一些注释,希望这不是一个XY 问题:我有一个具有许多复杂依赖项的项目,我知道如何使用 CMake 但不是直接从 g++ 构建。 I was able to build a shared library from this project that I could then link into an "R compatible" shared library ( R CMD SHLIB -o test.so test.cpp -L/path/to/my/lib/ -l my_lib_name ) which I was able to dyn.load() into my R environment.我能够从这个项目构建一个共享库,然后我可以链接到一个“R 兼容”共享库( R CMD SHLIB -o test.so test.cpp -L/path/to/my/lib/ -l my_lib_name ) 我能够将dyn.load()到我的 R 环境中。 At that point I then ran into the above .C vs. .Call issue.那时我遇到了上述.C.Call问题。

From reading some additional documentation (that I should have found on the first pass), I believe that you cannot .Call a function that has a return type of void .通过阅读一些额外的文档(我应该在第一遍中找到),我相信你不能。调用返回类型为void.Call I could not find an explicit mention of this, but no example in the documentation (eg this section ) listed a return type other than SEXP and at one point the documentation states that:我找不到明确提及这一点,但文档中没有示例(例如this section )列出了SEXP以外的返回类型,并且文档中有一次声明:

All the R objects you will deal with will be handled with the type 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: 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:

Note that the compiled code should not return anything except through its arguments: C functions should be of type void and Fortran subprograms should be subroutines.请注意,编译后的代码不应返回任何内容,除非通过其 arguments:C 函数应为 void 类型,Fortran 子程序应为子例程。

Here are some examples that can be compiled as in the OP.以下是一些可以在 OP 中编译的示例。 It didn't seem like there was a default "null" return type for .Call 'ed functions, but allocVector(REALSXP, 0) R_NilValue seemed to work well. .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;
} 

Here they are called from R.在这里,它们被称为 R。 Note we can send the ( void ) output to the dummy variable x if we don't want to see it.请注意,如果我们不想看到它,我们可以将 ( void ) output 发送到虚拟变量x

> dyn.load("test.so")

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

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

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

In general, the documentation linked above was pretty helpful, I recommend starting there for anyone with a similar question, I certainly wish I'd read it more thoroughly earlier on.一般来说,上面链接的文档很有帮助,我建议任何有类似问题的人从那里开始,我当然希望我能早点更彻底地阅读它。

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

相关问题 为什么 C++ 中的 fetestexcept 编译为 function 调用而不是内联 - Why is fetestexcept in C++ compiled to a function call rather than inlined 为什么会出现段错误(C ++ 98)? - Why do I get a segfault error (C++ 98)? 在C ++中使用[]而不是函数调用 - Using [] rather than a function call in c++ 为什么当我在 C++ 中使用 file.peek() 时,我得到的是数字而不是字符? - Why when I am using file.peek() in C++ do I get a number rather than the char? 为什么当我使用线程局部变量调用函数时,这个 nostdlib C++ 代码会出现段错误? 但不是使用全局变量或当我访问成员时? - Why does this nostdlib C++ code segfault when I call a function with a thread local variable? But not with a global var or when I access members? C ++函数在静态函数上调用segfault - C++ function call segfault on static function 调用方法c ++时出现段错误 - Segfault when calling a method c++ 创建C#到C ++的桥梁:为什么在调用DLL时会出现AccessViolationException? - Creating C# to C++ bridge: Why do I get a AccessViolationException when calling DLL? C ++为什么我要使用#define而不是内联? - C++ why would I use #define rather than inline? 将数组传递给C ++函数时出现段错误 - Segfault when passing array to C++ function
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM