This article is about what actually crosses the R/C boundary in Rtinycc:
The statements below are based on the implemented wrapper generator and runtime helpers.
Scalar inputs are converted at the boundary. For example:
i8, i16, i32, u8, u16 use integer coercion plus range checksi64, u32, u64 use numeric coercion plus integer-value checksbool rejects NAf32 and f64 are read from R numericsSo scalar arguments are not zero-copy views into R objects. They become C scalars inside the wrapper.
The array input types:
rawinteger_arraynumeric_arraylogical_arrayare passed as direct pointers into the underlying R vector storage.
That means:
This is the main zero-copy part of the FFI boundary.
cstring_array Is Rebuilt Per Callcstring_array is different. The wrapper allocates a temporary const char **
with R_alloc() and fills it by translating each R string element.
So:
Array returns are always copied into a newly allocated R vector. The wrapper
uses the declared length_arg to size the R result, then memcpy() copies the
returned C buffer into that vector.
If free = TRUE, the wrapper also frees the original returned buffer after the
copy.
So array returns are not borrowed views into C memory.
cstring Values Are CopiedFor cstring returns, the wrapper creates an R string with mkString() when
the returned pointer is non-NULL.
That means the resulting R value is a copy in R-managed memory, not a retained external pointer to the original C string.
ptr Values Stay as PointersFor ptr returns, the wrapper constructs an external pointer around the raw
address.
That means:
The same distinction matters for globals and struct fields.
sexp Passes Through Directlysexp is the most direct boundary mode:
sexp arguments are passed through as SEXPsexp values are returned directlyThis is useful when you want the R C API contract rather than the stricter FFI conversion layer.
At the helper level:
tcc_malloc() and tcc_cstring() create owned external pointerstcc_data_ptr() and tcc_read_ptr() return borrowed external pointersstruct_outer_get_child() return borrowed
nested views into the owning struct storageUse tcc_ptr_is_owned() when you need to distinguish these cases in R code.
Bitfield helpers behave like scalar getter/setter helpers at the R boundary, but that does not make them ordinary addressable fields.
In particular:
tcc_field_addr() and tcc_container_of() reject bitfield membersSo bitfields are intentionally excluded from the borrowed-address helper model.
Compiled tcc_compiled objects store enough recipe information to recompile
after serialize() / unserialize() or readRDS().
Raw pointers and raw tcc_state objects do not gain that behavior. After
serialization they are just dead addresses or invalid states, not
auto-reconstructed resources. The same applies to callback tokens,
struct/union external pointers, and helper allocations from tcc_malloc() or
tcc_cstring(): they do not serialize as live native resources.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.