0Pricing
Lua Academy · レッスン

コールバック: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フィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. FFIの基礎:ffi.cdefとffi.load
  2. FFIによるC関数の呼び出し
  3. FFIにおけるポインター、構造体、配列
  4. コールバック:Lua関数をCに渡す
← Lua Academyに戻る