0Pricing
Lua Academy · Урок

Обратные вызовы: передача функций Lua в C

Используйте ffi.cast для создания обратных вызовов C, обращающихся к коду Lua.

«Обратные вызовы: передача функций Lua в C» — бесплатный урок Lua Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Lua Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Lua Academy содержит 4 уроков всего.

Что такое обратные вызовы C

Некоторые API C требуют передать указатель на функцию, которую затем вызовет код C. FFI позволяет с помощью ffi.cast создавать совместимые с C указатели на функции из функций Lua.

Объявление типа обратного вызова

Сначала объявите тип указателя на функцию в 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)

Время жизни обратного вызова

Храните ссылку Lua на объект обратного вызова (cb). Если он будет удалён сборщиком мусора, вызов указателя на функцию C приведёт к сбою. Сохраните его в переменной или таблице с длительным временем жизни.

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

Сортировка с компаратором C

Передайте компаратор Lua функции C qsort через обратный вызов FFI.

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

Обратные вызовы и сопрограммы

Обратные вызовы Lua, вызванные из C, не могут приостанавливать выполнение (вызывать coroutine.yield). Сторона C не поддерживает переключение сопрограмм Lua. Проектируйте обратные вызовы так, чтобы они не приостанавливались.

Замыкания в обратных вызовах

Обратные вызовы Lua могут обычным образом захватывать внешние локальные значения. Благодаря этому обратные вызовы получают доступ к контексту (например, к объекту или таблице состояния) без глобальных переменных.

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

Обработчики сигналов

Регистрируйте функции Lua как обработчики сигналов Unix через FFI. Будьте осторожны: обработчики сигналов имеют строгие ограничения на вызываемые ими функции C.

Управление памятью обратных вызовов

Освобождайте обратные вызовы с помощью cb:free() после отмены регистрации на стороне C. Утечки объектов обратных вызовов приводят к напрасному расходу памяти.

Альтернатива: функции-обёртки на C

Для сложных интеграций тонкая прослойка на C может быть удобнее обратных вызовов FFI. Прослойка обращается обратно к Lua через API C, обеспечивая полный контроль над сопрограммами и обработкой ошибок.

Производительность

Обратные вызовы FFI быстры, но уступают по скорости прямым вызовам FFI, поскольку переход из C в Lua требует дополнительных затрат на подготовку. Для очень частых обратных вызовов (например, при обработке аудио) рассмотрите реализацию полностью на C.

Вопрос об обратном вызове

Почему необходимо сохранять ссылку Lua на объект обратного вызова FFI?

Повторение: обратные вызовы FFI

Используйте ffi.cast("fn_ptr_type", luaFunc) для создания обратных вызовов, совместимых с C. Всегда сохраняйте ссылку, чтобы предотвратить сборку мусора. Обратные вызовы не могут приостанавливать выполнение. Используйте внешние значения для передачи контекста в обратные вызовы.

Часто задаваемые вопросы

Урок «Обратные вызовы: передача функций Lua в C» бесплатный?

Да — полный текст урока «Обратные вызовы: передача функций Lua в C» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.

Чему я научусь в уроке «Обратные вызовы: передача функций Lua в C»?

Используйте ffi.cast для создания обратных вызовов C, обращающихся к коду Lua. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Lua Academy?

Предыдущий опыт не требуется. Lua Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Обратные вызовы: передача функций Lua в C»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Lua Academy?

Да. Каждый урок Lua Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы FFI: ffi.cdef и ffi.load
  2. Вызов функций C через FFI
  3. Указатели, структуры и массивы в FFI
  4. Обратные вызовы: передача функций Lua в C
← Назад к Lua Academy