The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Calling R from C

Introduction

Calling an R function from C involves:

Creating the special list for the call can be done using the helper methods lang1() to lang6(), or for R 4.4.1 or later allocLang() can provide more flexibility if needed.

lang1() - Calling an R function with no arguments

lang1() is for assembling a call to an R function without specifying any arguments.

In this example getwd() is called from C using lang1()

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

SEXP call_r_from_c_with_lang1(void) {

  SEXP my_call = PROTECT(lang1(
    PROTECT(Rf_install("getwd"))
  ));

  SEXP my_result = PROTECT(eval(my_call, R_GlobalEnv)); 

  UNPROTECT(3);
  return my_result;
}
Click to show R code
code = r"(
#include <R.h>
#include <Rinternals.h>

SEXP call_r_from_c_with_lang1(void) {

  SEXP my_call = PROTECT(lang1(
    PROTECT(Rf_install("getwd"))
  ));

  SEXP my_result = PROTECT(eval(my_call, R_GlobalEnv)); 

  UNPROTECT(3);
  return my_result;
}
)"

callme::compile(code)
call_r_from_c_with_lang1()
#> [1] "/private/var/folders/kq/h7dv19mj00947dthlyb5w2780000gn/T/Rtmp9tjFPt/Rbuild41a847919b5/callme/vignettes"

lang2() - Calling an R function with a single unnamed argument

lang2() is for assembling a call to an R function and specifying a single argument.

In this example abs(-1) is called from C using lang2()

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

SEXP call_r_from_c_with_lang2(void) {

  SEXP val = PROTECT(ScalarReal(-1));
  SEXP my_call = PROTECT(lang2(
    PROTECT(Rf_install("abs")),
    val
  ));

  SEXP my_result = PROTECT(eval(my_call, R_GlobalEnv)); 

  UNPROTECT(4);
  return my_result;
}
Click to show R code
code = r"(
#include <R.h>
#include <Rinternals.h>

SEXP call_r_from_c_with_lang2(void) {

  SEXP val = PROTECT(ScalarReal(-1));
  SEXP my_call = PROTECT(lang2(
    PROTECT(Rf_install("abs")),
    val
  ));

  SEXP my_result = PROTECT(eval(my_call, R_GlobalEnv)); 

  UNPROTECT(4);
  return my_result;
}
)"

callme::compile(code)
call_r_from_c_with_lang2()
#> [1] 1

lang2() - Calling an R function with a single named argument

In this example tempfile(fileext = ".txt") is called from C using lang2()

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

SEXP call_r_from_c_with_lang2_named(void) {
 
  // Assemble the function + argument with name
  SEXP val = PROTECT(mkString(".txt"));
  SEXP my_call = PROTECT(lang2(
    PROTECT(Rf_install("tempfile")),
    val
  ));

  // Set the argument name
  SEXP t = CDR(my_call);
  SET_TAG(t, Rf_install("fileext"));
  
  // Evaluate the call
  SEXP my_result = PROTECT(eval(my_call, R_GlobalEnv)); 

  UNPROTECT(4);
  return my_result;
}
Click to show R code
code = r"(
#include <R.h>
#include <Rinternals.h>

SEXP call_r_from_c_with_lang2_named(void) {
 
  // Assemble the function + argument with name
  SEXP val = PROTECT(mkString(".txt"));
  SEXP my_call = PROTECT(lang2(
    PROTECT(Rf_install("tempfile")),
    val
  ));

  // Set the argument name
  SEXP t = CDR(my_call);
  SET_TAG(t, Rf_install("fileext"));
  
  // Evaluate the call
  SEXP my_result = PROTECT(eval(my_call, R_GlobalEnv)); 

  UNPROTECT(4);
  return my_result;
}
)"

callme::compile(code)
call_r_from_c_with_lang2_named()
#> [1] "/var/folders/kq/h7dv19mj00947dthlyb5w2780000gn/T//RtmpzTwosz/file41d27bc04afb.txt"

Using allocLang() (R >= 4.4.1 only)

The C code is equivalent to this R code:

print(pi , digits = 3)
#include <R.h>
#include <Rinternals.h>

SEXP call_print_from_c(SEXP value, SEXP digits) {
  // Allocate a new call object
  SEXP my_call = PROTECT(allocLang(3));

  // Manipulate a pointer to this call object to 
  // fill in the arguments and set argument names 
  SEXP t = my_call;
  SETCAR(t, install("print")); t = CDR(t);
  SETCAR(t,  value)          ; t = CDR(t);
  SETCAR(t, digits);
  SET_TAG(t, install("digits"));
  eval(my_call, R_GlobalEnv);

  UNPROTECT(1);
  return R_NilValue;
}
Click to show R code
code = r"(
#include <R.h>
#include <Rinternals.h>

SEXP call_print_from_c(SEXP value, SEXP digits) {
  // Allocate a new call object
  SEXP my_call = PROTECT(allocLang(3));

  // Manipulate a pointer to this call object to 
  // fill in the arguments and set argument names 
  SEXP t = my_call;
  SETCAR(t, install("print")); t = CDR(t);
  SETCAR(t,  value)          ; t = CDR(t);
  SETCAR(t, digits);
  SET_TAG(t, install("digits"));
  eval(my_call, R_GlobalEnv);

  UNPROTECT(1);
  return R_NilValue;
}
)"

callme::compile(code)
call_print_from_c(pi, digits = 3)

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.