0Pricing
Lua Academy · 课时

回调:将 Lua 函数传递给 C

使用 ffi.cast 创建可回调 Lua 代码的 C 回调函数。

回调:将 Lua 函数传递给 C 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Lua Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Lua Academy 课程共包含 4 节课。

什么是 C 回调?

某些 C API 要求您传入一个函数指针,由 C 代码进行回调。FFI 的 ffi.cast 可以从 Lua 函数创建兼容 C 的函数指针。

声明回调类型

首先在 cdef 中声明函数指针类型。

local ffi = require("ffi")
ffi.cdef[[
  typedef void (*callback_t)(int event, void *data);
  void register_handler(callback_t cb);
]]

创建回调

使用 ffi.cast("callback_t", luaFunc) 将 Lua 函数包装为 C 回调。结果是一个 C 函数指针,可以传递给 C 代码。

local function myHandler(event, data)
  print("Event:", event)
end
local cb = ffi.cast("callback_t", myHandler)
lib.register_handler(cb)

回调生命周期

请保留对回调对象(cb)的 Lua 引用。如果它被 GC 回收,调用该 C 函数指针就会崩溃。请将它存储在生命周期较长的变量或表中。

local callbacks = {}  -- prevent GC
callbacks[#callbacks+1] = ffi.cast("callback_t", myHandler)
lib.register_handler(callbacks[#callbacks])

使用 C 比较器排序

通过 FFI 回调将 Lua 比较器传递给 C 的 qsort。

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

回调与协程

从 C 调用的 Lua 回调不能让出(调用 coroutine.yield)。C 端不支持 Lua 的协程切换。请将回调设计为不可让出的函数。

回调中的上值

Lua 回调可以正常捕获上值。这样,回调无需使用全局变量即可访问上下文(例如对象或状态表)。

local function makeHandler(ctx)
  return ffi.cast("callback_t", function(event, _)
    ctx.lastEvent = event  -- upvalue access
  end)
end

信号处理器

通过 FFI 将 Lua 函数注册为 Unix 信号处理器。请注意:信号处理器能够调用哪些 C 函数受到严格限制。

回调内存管理

从 C 端注销回调后,使用 cb:free() 释放回调。泄漏回调对象会浪费内存。

替代方案:C 包装函数

对于复杂的集成,使用轻量的 C 适配层可能比 FFI 回调更简洁。适配层通过 C API 回调 Lua,从而可以完全控制协程和错误处理。

性能

FFI 回调速度很快,但不如直接的 FFI 调用,因为 C 到 Lua 的桥接需要额外的准备开销。对于非常高频的回调(例如音频处理),可以考虑使用纯 C 实现。

回调问题

为什么必须保留对 FFI 回调对象的 Lua 引用?

回顾:FFI 回调

使用 ffi.cast("fn_ptr_type", luaFunc) 创建兼容 C 的回调。请始终保存一个引用,以防止垃圾回收。回调不能执行 yield。请使用上值将上下文传入回调。

常见问题解答

「回调:将 Lua 函数传递给 C」课时是免费的吗?

是的 — 「回调:将 Lua 函数传递给 C」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。

「回调:将 Lua 函数传递给 C」这节课中我会学到什么?

使用 ffi.cast 创建可回调 Lua 代码的 C 回调函数。 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Lua Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「回调:将 Lua 函数传递给 C」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Lua Academy 课中编写并运行代码吗?

能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. FFI 基础:ffi.cdef 和 ffi.load
  2. 通过 FFI 调用 C 函数
  3. FFI 中的指针、结构体和数组
  4. 回调:将 Lua 函数传递给 C
← 返回 Lua Academy