I am using .Call for the first time. I wrote the simple code below, where I pass an integer and return an SEXP (to R):
#include <R.h>
#include <Rdefines.h>
SEXP setInt(int *a) {
SEXP myint;
int *p_myint;
int len = 5;
PROTECT(myint = NEW_INTEGER(len)); // Allocating storage space
p_myint = INTEGER_POINTER(myint); // ponit to SEXP object
p_myint[0] = *a;
UNPROTECT(1);
return myint;
}
Thus, I call R CMD SHLIB which creates the dll (no problem here).
When run the code below (in R), I get an answer different than c(100,0,0,0,0):
> dyn.load(file.path(path.dll,paste0("useC", .Platform$dynlib.ext)))
> a<-100
> out<- .Call("setInt",as.integer(a))
> out
[1] 536870925 0 0 0 0
P.S: Probably I am getting the value of the address of pointer variable "a", instead of its value. But I don't know what I am missing here.
EDIT:
Using the answer of @JoshuaUlrich I fixed the code and added more features. The fixed code is:
SEXP setInt(SEXP a,SEXP pos) {
SEXP myint;
int *p_a;
int *p_myint;
int len = 5;
PROTECT(myint = NEW_INTEGER(len)); // Allocate storage space, with default 5 zeroes
p_myint = INTEGER_POINTER(myint); // ponit to SEXP object
p_a = INTEGER_POINTER(a);
p_myint[0] = p_a[(asInteger(pos)-1)]; // get the element at pos
UNPROTECT(1);
return myint;
}
When calling from R you get:
a<-c(100,200,300)
pos<-1
out<- .Call("setInt",as.integer(a),as.integer(pos))
> out
[1] 100 0 0 0 0
pos<-2
out<- .Call("setInt",as.integer(a),as.integer(pos))
> out
[1] 200 0 0 0 0
Your setInt
function definition accepts a C int as its only argument. But in your R code, you're passing a INTSXP
, not a C int. In general, C functions called via .Call
should only accept SEXP as arguments.
So change your function definition to:
SEXP setInt(SEXP a) {
SEXP myint;
int *p_myint;
int len = 5;
PROTECT(myint = NEW_INTEGER(len)); // Allocating storage space
p_myint = INTEGER_POINTER(myint); // ponit to SEXP object
p_myint[0] = AS_INTEGER(a);
UNPROTECT(1);
return myint;
}
Also note that you should probably ensure a
is INTSXP
and length(a)==1
. If length(a) > 1
, you can do this:
int *p_a;
p_a = INTEGER_POINTER(a);
p_myint[0] = p_a[1]; // get second element from a
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With