Callbacks: Passing Lua Functions to C
Use ffi.cast to create C callbacks that call back into Lua code.
Callbacks: Passing Lua Functions to C is a free Lua Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Lua Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Are C Callbacks?
Some C APIs require you to pass a function pointer that the C code will call back. The FFI's ffi.cast lets you create C-compatible function pointers from Lua functions.
Declaring a Callback Type
First declare the function pointer type in cdef.
local ffi = require("ffi")
ffi.cdef[[
typedef void (*callback_t)(int event, void *data);
void register_handler(callback_t cb);
]]Creating a Callback
Use ffi.cast("callback_t", luaFunc) to wrap a Lua function as a C callback. The result is a C function pointer that can be passed to C code.
local function myHandler(event, data)
print("Event:", event)
end
local cb = ffi.cast("callback_t", myHandler)
lib.register_handler(cb)Callback Lifetime
Keep a Lua reference to the callback object (cb). If it is GC'd, calling the C function pointer will crash. Store it in a long-lived variable or table.
local callbacks = {} -- prevent GC
callbacks[#callbacks+1] = ffi.cast("callback_t", myHandler)
lib.register_handler(callbacks[#callbacks])Sorting with a C Comparator
Pass a Lua comparator to C's qsort via FFI callback.
ffi.cdef[[
typedef int (*cmp_t)(const void *a, const void *b);
void qsort(void *base, size_t nmemb, size_t size, cmp_t cmp);
]]
local arr = ffi.new("int[5]", {3,1,4,1,5})
local cmp = ffi.cast("cmp_t", function(a, b)
return ffi.cast("int*", a)[0] - ffi.cast("int*", b)[0]
end)
ffi.C.qsort(arr, 5, ffi.sizeof("int"), cmp)
for i = 0, 4 do io.write(arr[i] .. " ") endCallbacks and Coroutines
Lua callbacks called from C cannot yield (call coroutine.yield). The C side does not support Lua's coroutine switch. Design callbacks to be non-yielding.
Upvalues in Callbacks
Lua callbacks can capture upvalues normally. This lets callbacks access context (e.g., an object or state table) without global variables.
local function makeHandler(ctx)
return ffi.cast("callback_t", function(event, _)
ctx.lastEvent = event -- upvalue access
end)
endSignal Handlers
Register Lua functions as Unix signal handlers via FFI. Be careful: signal handlers have severe restrictions on what C functions they can call.
Callback Memory Management
Release callbacks with cb:free() after deregistering from the C side. Leaking callback objects wastes memory.
Alternative: C Wrapper Functions
For complex integrations, a thin C shim may be cleaner than FFI callbacks. The shim calls back into Lua via the C API, giving full control over coroutine and error handling.
Performance
FFI callbacks are fast but not as fast as direct FFI calls, since the C-to-Lua bridge involves setup overhead. For very high-frequency callbacks (e.g., audio), consider pure C implementations.
Callback Question
Why must you keep a Lua reference to an FFI callback object?
Recap: FFI Callbacks
Use ffi.cast("fn_ptr_type", luaFunc) to create C-compatible callbacks. Always store a reference to prevent GC. Callbacks cannot yield. Use upvalues to pass context into callbacks.
Frequently asked questions
Is the “Callbacks: Passing Lua Functions to C” lesson free?
Yes — the full text of “Callbacks: Passing Lua Functions to C” is free to read here on the web, and the Lua Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Lua Academy course, upgrade to CoddyKit PRO.
What will I learn in “Callbacks: Passing Lua Functions to C”?
Use ffi.cast to create C callbacks that call back into Lua code. You practise Lua Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Lua Academy?
No prior experience is required. Lua Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Callbacks: Passing Lua Functions to C” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Lua Academy lesson?
Yes. Every Lua Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- FFI Basics: ffi.cdef and ffi.load
- Calling C Functions via FFI
- Pointers, Structs, and Arrays in FFI
- Callbacks: Passing Lua Functions to C