Awesome
<!-- README.md is generated from README.Rmd. Please edit that file -->simplec - demo package for calling C code with .C()
<!-- badges: start -->
<!-- badges: end -->
simplec
is a small demo package showing how C code could be included
in a package and called with .C()
In general: Consider using .Call()
or Rcpp
instead of .C()
This is one of a series of small demo packages for
calling other languages from R:
- {simplec} - calling C
with
.C()
- {simplecall} -
calling C with
.Call()
- {simplercpp} -
calling C++ with
{Rcpp}
- {simplefortran} -
calling Fortran with
.Fortran()
Rough comparison of .C()
, .Call()
, {Rcpp}
(and .Fortran()
)
.C() | .Call() | Rcpp | |
---|---|---|---|
Overview | No real understanding of R objects | Need to understand SEXP macros & internals | C++ classes hide the complexity of the SEXP internals |
What code? | Basic C code. Numeric calcs. | Complex C code. Can manipulate R objects from C | Complex C and C++ code involving numerics and R objects |
Pros | Simple to understand and use | Simple. No unnecessary copying. | Great documentation. Wrapping of R objects very intuitive. |
Cons | Too simple for most interesting things | Need to understand SEXP & R internals | |
Cons | Performs copying of data to call functions | ||
Demo R package | {simplec} | {simplecall} | {simplercpp} |
Compiled size | 17 kB | 17 kB | 92 kB (stripping can bring this down: see issue1) |
.Fortran() | |
---|---|
Overview | No real understanding of R objects |
What code? | Basic Fortran code. Numeric calcs. |
Pros | Simple to understand and use |
Cons | Too simple for most interesting things |
Cons | Performs copying of data to call functions |
Cons | Need to know Fortran! |
Demo R package | {simplefortran} |
Compiled size | 17 kB |
|
Installation
You can install from GitHub with:
# install.package('remotes')
remotes::install_github('coolbutuseless/simplec)
What’s in the box?
Package contains 2 C functions, and 2 functions in R which call the C
functions using .C()
.
C function | R function |
---|---|
add_(double *x, double *y, double *res) | add_C(x, y) |
mul_(double *x, double *y, double *res) | mul_C(x, y) |
What’s in the R functions?
- A call using
.C()
- First argument is the C function name e.g.
add_
x
andy
arguments are passed through from the R function- the third argument to the function is space in which to store the
result i.e.
numeric(1)
.C()
returns as many arguments as you gave it originally- We only want to return the actual result, which is the third
argument, hence
[[3]]
@useDynLib [packagename] [C function name]
is used to generate the NAMESPACE entryuseDynLib(simplec,add_)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#' Add two numbers
#'
#' @param x,y numbers to add
#'
#' @useDynLib simplec add_
#' @export
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
add_C <- function(x, y) {
.C(add_, x, y, numeric(1))[[3]]
}
What’s in the C functions?
- C function returns
void
- all arguments passed as pointers
- Actual result must be stored in one of the arguments
void add_(double* x, double* y, double* res) {
res[0] = x[0] + y[0];
}
How do R variables map to C variables?
- See R manual on writing Extensions for more info
R | C |
---|---|
logical | int * |
integer | int * |
double | double * |
complex | Rcomplex * |
character | char ** |
raw | unsigned char * |
What does the C function look like in R?
- An object of class
NativeSymbolInfo
- Holds an
externalptr
to the loaded function
simplec:::add_
#> $name
#> [1] "add_"
#>
#> $address
#> <pointer: 0x7f9780cb1c30>
#> attr(,"class")
#> [1] "RegisteredNativeSymbol"
#>
#> $dll
#> DLL name: simplec
#> Filename:
#> /Library/Frameworks/R.framework/Versions/4.0/Resources/library/simplec/libs/simplec.so
#> Dynamic lookup: FALSE
#>
#> $numParameters
#> [1] 3
#>
#> attr(,"class")
#> [1] "CRoutine" "NativeSymbolInfo"
Resources
- Peter Dalgaard’s Keynote from UseR 2004 discusses R’s language interfaces
- Using R — Calling C Code ‘Hello World’
- Hadley’s Advanced R book chapter - ‘Rs C interface’
- Rcpp
Acknowledgements
- R Core for developing and maintaining such a wonderful language.
- CRAN maintainers, for patiently shepherding packages onto CRAN and maintaining the repository