rdyncall is a low-level Foreign Function Interface (FFI)
for R. It lets you load shared C libraries, resolve symbols, and call C
functions directly from R when you know the C declaration you want to
bind.
It is useful for exploration, prototypes, dynamic bindings, and small
direct interfaces. For stable high-level R packages, a compiled
.Call wrapper may still be the better long-term
interface.
Use this article when you already know one C declaration and want to prove that R can load the library, resolve the symbol, call the function, and handle the basic data shapes involved. It is the shortest path through the package before moving on to signatures, memory layouts, callbacks, or generated bindings.
A first direct call
The basic workflow has three steps:
- Find or load a shared library.
- Resolve a function symbol.
- Call the address with a signature that matches the C function type.
The C math function is declared as:
The corresponding rdyncall call signature is "d)d": one
double argument, then ), then a
double return value.
math_names <- c("msvcrt", "m", "m.so.6")
mathlib <- dynfind(math_names)
sqrt_addr <- dynsym(mathlib, "sqrt")
dyncall(sqrt_addr, "d)d", 144)
#> [1] 12If the signature does not match the real C function type, the process can crash. Keep the C declaration beside the R binding while you develop.
Wrap the same idea
dynbind() creates thin R wrappers for one or more
functions in a library. The wrapper still uses the same signature
internally, but the call site becomes ordinary R code.
Call an R function through a C callback pointer
ccallback() turns an R function into a C function
pointer. The signature describes the callback function type.
Keep an R reference to callback objects for as long as foreign code may call them. If a callback is garbage-collected while C still holds its pointer, the next C call can crash R.
Describe and use a C struct
C aggregate types are registered with compact structure signatures. This C type:
can be registered and used from R:
cstruct("ArticleRect{ssSS}x y w h;")
rect <- cdata(ArticleRect)
rect$x <- 40L
rect$y <- 60L
rect$w <- 10L
rect$h <- 15L
rect$w * rect$h
#> [1] 150cdata() returns a raw-backed object with struct
metadata. Field access reads and writes the raw bytes according to the
registered layout.
Next steps
- Use signatures to translate C declarations into rdyncall signatures.
- Use structs, unions, and memory for aggregate layouts and raw memory access.
- Use callbacks when a C API stores and later calls an R function pointer.
- Use dynbind and dynport for larger bindings.
- Use troubleshooting when a library, symbol, signature, or pointer does not behave as expected.