2017-07-22 1 views
-2

Ich versuche, eine einfache Integration von R mit C zu implementieren. Zunächst ist es einfach: Ich möchte bestehen Werte von R zu einer C-Funktion integriert in eine .o Shared Library über .C oder .Call Funktion. Die C-Funktion sollte einfach die über printf übergebenen Werte ausdrucken.Empfangen *** gefangen segfault ***, "Speicher nicht gemappt" und Mangled Ergebnisse nach dem Passieren von Werten von R bis C

Hier ist meine .Call Methode:

.Call("test", as.integer(5), as.character("A"), as.character("string_test")) 

Und meine C-Code:

#include <stdio.h> 

void test(int integer, char character, char **str) { 
     printf("Integer: %i\nChar: %c\nString: %s\n", integer, character, *str); 
} 

Aber wenn ich die C-Funktion von R über eine Konsole aufrufen (RStudio abstürzt) mit gdb aktiviert ist, erhalte ich:

Integer: 1466480376 
Char: � 
Float: -100407552.000000 
String: 
***caught segfault *** 
address 0x20000090, cause 'memory not mapped' 

Traceback: 
1: .Call("test", as.integer(5), as.character("A"), as.character("string_test")) 

Als ob es nicht genug wäre, wie wir die Werte Pas sehen können sed in sind sehr seltsam gedruckt.

Einzelheiten von dem, was ich tat, Schritt für Schritt:

Ich baute die .o gemeinsam benutzte Bibliothek mit gcc:

gcc -shared -o func_teste.o -fPIC func_teste.c 

Und für dynamische Belastung in R-Umgebung vorbereitet:

$ R CMD SHLIB func_teste.o 
gcc -m64 -I/usr/include/R -DNDEBUG -I/usr/local/include -fpic -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic -c func_teste.c -o func_teste.o 
gcc -m64 -shared -L/usr/lib64/R/lib -Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -o func_teste.so func_teste.o -L/usr/lib64/R/lib -lR 

Und schließlich, innerhalb der R-Konsole lief ich:

Hat jemand eine Idee, warum das passiert?

+7

Es sieht so aus, als ob GNU (oder das R-Team) eine hervorragende Dokumentation bietet. Siehe auch [Schreiben von R-Erweiterungen] (https: // cran.r-project.org/doc/manuals/r-release/R-exts.html). Allgemeiner, siehe [Die R Handbücher] (https://cran.r-project.org/manuals.html). Ich bin irgendwie neidisch darauf, wie gut die Docs sind. – jww

+0

OP scheint '.C()' Aufrufkonvention mit '.Call()' usage zu verwechseln. –

Antwort

2

R bietet zwei Hauptfunktionen für von C-Code Schnittstelle (und damit C++ Code oder jede andere Sprache kann eine C-Schnittstelle verwenden): - .C() ist die ältere Schnittstelle int*, mit double* ... und gleich - .Call() ist die neuere, leistungsfähigere Schnittstelle Jetzt SEXP Objekte

verwenden, .Call() sieht komplizierter aus, aber es ist so viel mächtiger sowie sicherer. Es gibt nahezu universellen Konsens, dass nicht mehr verwendet werden sollte (siehe verschiedene Diskussionen auf der R-DEVEL-Liste und anderen Stellen).

Der Hauptnachteil mit .Call() ist, dass Sie lernen müssen, wie Sie Ihre Werte packen und entpacken. Oder ... du betrügst und lässt Rcpp es für dich tun. Also mit diesem, hier ist einzeilige Lösung aus dem Beispiel des OP:

> library(Rcpp) 
> cppFunction("void mytest(int i, char c, std::string str) { printf(\"Integer: %i Char: %c String: %s\\n\", i, c, str.c_str()); }") 
> mytest(42L, 'Q', "a boat") 
Integer: 42 Char: Q String: a boat 
> 

Ich habe die char* eine Zeichenfolge. Beachten Sie, dass cppFunction() erfordert das Entkommen von Strings, können Sie in sourceCpp() und Pakete für echte Arbeit suchen. Die Rcpp-Dokumentation enthält Details.

Verwandte Themen