Lua Academy · Lesson

Callbacks: Passing Lua Functions to C

Use ffi.cast to create C callbacks that call back into Lua code.

Lesson 4 of 413 steps

Callbacks: Passing Lua Functions to C is a free Lua Academy lesson on CoddyKit. This is lesson 4 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Lua Academy learning path, and your progress syncs across the web and the CoddyKit app. The Lua Academy course includes 4 lessons in total.

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.

Free to start

Learn Lua with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
40
Lessons
159

Frequently Asked Questions

Is the “Callbacks: Passing Lua Functions to C” lesson free?

Yes — any 3 lessons of the Lua Academy learning path, including “Callbacks: Passing Lua Functions to C”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Lua Academy course includes 4 lessons in total.

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, so you can start here or from the beginning and move at your own pace. This is lesson 4 of 4.

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