Calling R from C

knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
knitr::knit_engines$set(callme = callme:::callme_engine)
library(callme)

```{css, echo=FALSE} .callme { background-color: #E3F2FD; } pre.callme span { background-color: #E3F2FD; }

## Introduction

Calling an R function from C involves:

* Creating a special list of function name and arguments
* Optionally setting the argument names with `SET_TAG()`
* Calling `eval()`

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()`

```{callme}
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;
}
call_r_from_c_with_lang1()

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()

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;
}
call_r_from_c_with_lang2()

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

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

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;
}
call_r_from_c_with_lang2_named()

Using allocLang() (R >= 4.4.1 only)

The C code is equivalent to this R code:

print(pi , digits = 3)

```{callme eval=(getRversion() >= "4.4.1")}

| invisible=TRUE, compile=FALSE

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; }

```r
call_print_from_c(pi, digits = 3)


Try the callme package in your browser

Any scripts or data that you put into this service are public.

callme documentation built on April 4, 2025, 2:37 a.m.