簡體   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