コールバック:Lua関数をCに渡す
ffi.castで、Luaコードを呼び出すCコールバックを作成します。
「コールバック:Lua関数をCに渡す」はCoddyKit上の無料Lua Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応の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コールバックは、yield(coroutine.yieldの呼び出し)できません。C側はLuaのコルーチン切り替えをサポートしていないためです。コールバックはyieldしないように設計してください。
コールバック内のupvalue
Luaのコールバックでは通常どおりupvalueをキャプチャできます。これにより、グローバル変数を使わずに、コールバックからコンテキスト(例:オブジェクトや状態テーブル)へアクセスできます。
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ラッパー関数
複雑な連携では、FFIコールバックより薄いCシムのほうが明快な場合があります。シムはC APIを介してLuaを呼び出すため、コルーチンやエラー処理を完全に制御できます。
性能
FFIコールバックは高速ですが、CからLuaへのブリッジにはセットアップのオーバーヘッドがあるため、直接のFFI呼び出しほど高速ではありません。非常に高頻度のコールバック(例:オーディオ)では、Cだけで実装することを検討してください。
コールバックに関する質問
なぜ FFI コールバックオブジェクトへの Lua の参照を保持する必要がありますか?
まとめ: FFI コールバック
ffi.cast("fn_ptr_type", luaFunc) を使用して C 互換のコールバックを作成します。GC による回収を防ぐため、必ず参照を保持します。コールバックからは yield できません。upvalue を使用してコールバックにコンテキストを渡します。
よくある質問
「コールバック:Lua関数をCに渡す」レッスンは無料ですか?
はい。「コールバック:Lua関数をCに渡す」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Lua Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Lua Academyコースには全4レッスンが含まれています。
「コールバック:Lua関数をCに渡す」で何を学びますか?
ffi.castで、Luaコードを呼び出すCコールバックを作成します。 ブラウザで直接実行するハンズオンコードでLua Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Lua Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLua Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「コールバック:Lua関数をCに渡す」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLua Academyレッスンでコードを書いて実行できますか?
はい。すべてのLua Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- FFIの基礎:ffi.cdefとffi.load
- FFIによるC関数の呼び出し
- FFIにおけるポインター、構造体、配列
- コールバック:Lua関数をCに渡す