infix is a modern, lightweight C library that lets you call any C function or create C callbacks at runtime, using simple, human-readable strings to describe the function's signature.
It's designed to be the simplest way to add a dynamic Foreign Function Interface (FFI) to your project, whether you're building a language runtime, a plugin system, or just need to call functions from a dynamically loaded library.

Key Features
- Human-Readable Signatures: Describe complex C functions with an intuitive string format (e.g.,
"({double, double}, int) -> *char").
- Forward & Reverse Calls: Call C functions ("forward") and create C function pointers that call back into your code ("reverse").
- Direct Marshalling API: Build high-performance language bindings where the JIT compiler calls your object-unboxing functions directly, bypassing intermediate buffers.
- Simple Integration: Add a single C file and a header directory to your project to get started. No complex dependencies.
- Type Registry: Define, reuse, and link complex, recursive, and mutually-dependent structs by name.
- Security-First Design: Hardened against vulnerabilities with Write XOR Execute (W^X) memory, guard pages, and fuzz testing.
- High Performance: A Just-in-Time (JIT) compiler generates optimized machine code trampolines, making calls nearly as fast as a direct C call after the initial setup.
Full Documentation
How It Works: A Quick Example
The heart of infix is its signature string. Here’s how you would call a simple C function:
#include <stdio.h>
int add(
int a,
int b) {
return a + b; }
const char* signature = "(int, int) -> int";
int a = 10, b = 32;
void*
args[] = { &a, &b };
int result;
printf("Result: %d\n", result);
return 0;
}
void * args[]
Definition 202_in_structs.c:57
int main(void)
Definition 821_threading_bare.c:69
static int add(int a, int b)
Definition Ch04_ThreadSafety.c:25
void(* infix_cif_func)(void *, void **)
A function pointer type for a bound forward trampoline.
Definition infix.h:336
c23_nodiscard infix_status infix_forward_create(infix_forward_t **, const char *, void *, infix_registry_t *)
Creates a "bound" forward trampoline from a signature string.
Definition trampoline.c:989
c23_nodiscard infix_cif_func infix_forward_get_code(infix_forward_t *)
Gets the callable function pointer from a bound forward trampoline.
Definition trampoline.c:278
void infix_forward_destroy(infix_forward_t *)
Destroys a forward trampoline and frees all associated memory.
Definition trampoline.c:631
The public interface for the infix FFI library.
Internal definition of a forward trampoline handle.
Definition infix_internals.h:88
Creating Callbacks
infix can also generate native C function pointers that call back into your code. This is perfect for interfacing with C libraries that expect callbacks, like qsort.
#include <stdlib.h>
int compare_integers(const void* a, const void* b) {
return (*(const int*)a - *(const int*)b);
}
void run_qsort_example() {
const char* cmp_sig = "(*void, *void) -> int";
int numbers[] = { 5, 1, 4, 2, 3 };
qsort(numbers, 5, sizeof(int), my_comparator);
}
c23_nodiscard infix_status infix_reverse_create_callback(infix_reverse_t **, const char *, void *, infix_registry_t *)
Creates a type-safe reverse trampoline (callback).
Definition trampoline.c:1044
c23_nodiscard void * infix_reverse_get_code(const infix_reverse_t *)
Gets the native, callable C function pointer from a reverse trampoline.
Definition trampoline.c:895
void infix_reverse_destroy(infix_reverse_t *)
Destroys a reverse trampoline and frees all associated memory.
Definition trampoline.c:877
Internal definition of a reverse trampoline (callback/closure) handle.
Definition infix_internals.h:114
High-Performance Language Bindings
If you are writing a binding for a language like Python, Perl, or Lua, infix offers a specialized direct marshalling API. This allows the JIT compiler to call your object unboxing functions ("marshallers") directly, eliminating the need to allocate intermediate C arrays.
typedef struct { int type; union { int i; double d; } val; } PyObject;
PyObject* obj = (PyObject*)obj_ptr;
}
void run_binding_example(void* target_func) {
PyObject*
args[] = { py_obj1, py_obj2 };
}
infix_direct_arg_handler_t handlers[2]
Definition 901_call_overhead.c:103
c23_nodiscard infix_status infix_forward_create_direct(infix_forward_t **out_trampoline, const char *signature, void *target_function, infix_direct_arg_handler_t *handlers, infix_registry_t *registry)
Creates a forward trampoline with direct, JIT-bound marshalling.
Definition trampoline.c:1000
c23_nodiscard infix_direct_cif_func infix_forward_get_direct_code(infix_forward_t *trampoline)
Gets the callable function pointer from a direct marshalling trampoline.
Definition trampoline.c:283
infix_marshaller_fn scalar_marshaller
For "in" parameters of a scalar type (int, float, pointer).
Definition infix.h:1356
int64_t i64
Used for all signed integer types up to 64 bits.
Definition infix.h:1302
A struct containing all the necessary handlers for a single function argument.
Definition infix.h:1354
A union to hold any primitive value returned by a scalar marshaller.
Definition infix.h:1300
Getting Started
The easiest way to use infix is to add its source directly to your project.
- Copy the
src/ and include/ directories into your project.
- Add
src/infix.c to your build system's list of source files.
- Add the
include/ directory to your include paths.
#include <infix/infix.h> in your code.
For more advanced build options, including building as a standalone library with CMake or xmake, see the Building and Integration Guide.
Project Philosophy
infix is built on three core principles:
- Security First: An FFI library with a JIT is a prime target for vulnerabilities. We defend against these with a multi-layered approach, including strict W^X memory, hardened integer arithmetic, and continuous fuzz testing.
- Performance by Design: FFI overhead should be minimal.
infix separates the one-time generation cost from the near-zero call-time cost, making it exceptionally fast in high-performance applications when trampolines are cached.
- Simplicity and Portability: Platform- and ABI-specific logic is strictly isolated, making the library easy to maintain, simple to integrate, and straightforward to port to new architectures.
Platform Support
infix is rigorously tested on a wide array of operating systems, compilers, and architectures with every commit.
| OS | Version | Architecture | Compiler | Status |
| DragonflyBSD | 6.4.0 | x86-64 | GCC | |
| FreeBSD | 15.0 | x86-64 | GCC | |
| 15.0 | AArch64 | GCC | |
| 15.0 | RISC-V64 | GCC | |
| 15.0 | x86-64 | Clang | |
| 15.0 | AArch64 | Clang | |
| 15.0 | RISC-V64 | Clang | |
| macOS | Sequoia | AArch64 | Clang | |
| Sequoia | AArch64 | GCC | |
| NetBSD | 10.1 | AArch64 | GCC | |
| 10.1 | x86-64 | GCC | |
| OmniOS | r151054 | x86-64 | GCC | |
| OpenBSD | 7.8 | AArch64 | Clang | |
| 7.8 | AArch64 | GCC | |
| 7.8 | x86-64 | Clang | |
| 7.8 | x86-64 | Clang | |
| 7.8 | RISC-V64 | Clang | |
| 7.8 | RISC-V64 | GCC | |
| Solaris | 11.4 | x86-64 | GCC | |
| Ubuntu | 24.04 | AArch64 | Clang | |
| 24.04 | AArch64 | GCC | |
| 24.04 | x86-64 | Clang | |
| 24.04 | x86-64 | GCC | |
| Windows | Server 2025 | AArch64 | Clang | |
| Server 2025 | AArch64 | GCC | |
| Server 2025 | AArch64 | MSVC | |
| Server 2025 | x86-64 | Clang | |
| Server 2025 | x86-64 | GCC | |
| Server 2025 | x86-64 | MSVC | |
In addition to the CI platforms tested here on Github, I can verify infix builds and passes unit tests on Android/Termux.
Licenses
To maximize usability for all, infix is dual-licensed under the [Artistic License 2.0](LICENSE-A2) and the [MIT License](LICENSE-MIT). You may choose to use the code under the terms of either license.
At your discretion, all standalone documentation (.md), explanatory text, Doxygen-style documentation blocks, comments, and code examples contained within this repository may be used, modified, and distributed under the terms of the [Creative Commons Attribution 4.0 International License (CC BY 4.0)](LICENSE-CC). I encourage you to share and adapt the documentation for any purpose (generating an API reference website, creating tutorials, etc.), as long as you give appropriate credit.