0Pricing
Lua Academy · Lesson

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] .. " ") end

Callbacks 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)
end

Signal 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

  1. FFI Basics: ffi.cdef and ffi.load
  2. Calling C Functions via FFI
  3. Pointers, Structs, and Arrays in FFI
  4. Callbacks: Passing Lua Functions to C
← Back to Lua Academy