首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 模塊回調 Lua 函數的兩種核心模式詳解

     編輯:關於C語言

背景

Lua 與 C 通過虛擬棧交互,C 模塊需在特定時機調用 Lua 定義的回調函數。主要有兩種模式:註冊表引用與全局環境查找。

模式一:註冊表保存函數引用(推薦)

利用 luaL_ref 將棧頂函數存入註冊表,返回整數索引;調用時用 lua_rawgeti 取出再 lua_call。

C 實現

static int lua_callback = LUA_REFNIL; // 全局靜態變量持有引用 

static int setnotify(lua_State* L) { 
    lua_callback = luaL_ref(L, LUA_REGISTRYINDEX); // 彈棧頂函數,存註冊表 
    return 0; 
} 

static int testnotify(lua_State* L) { 
    lua_rawgeti(L, LUA_REGISTRYINDEX, lua_callback); // 取出函數壓棧 
    lua_call(L, 0, 0); // 調用:0參數,0返回值 
    return 0; 
}

Lua 調用

function callback() print("Callback from registry") end 
cb.setnotify(callback) -- 註冊 
cb.testnotify()        -- 觸發回調

模式二:直接訪問全局環境(簡便但耦合)

約定回調函數固定全局名(如 defcallback),C 代碼直接 lua_getglobal 查找調用。

C 實現

static int testenv(lua_State* L) { 
    lua_getglobal(L, "defcallback"); // 從 _G 取函數 
    lua_call(L, 0, 0); 
    return 0; 
}

Lua 端封裝隔離

local function my_callback() print("My logic") end 
function defcallback() my_callback() end -- 適配 C 固定名 
cb.testenv()

完整模塊代碼 cb.c

#include <stdio.h> 
#include <lua.h> 
#include <lualib.h> 
#include <lauxlib.h> 

static int lua_callback = LUA_REFNIL; 

static int setnotify(lua_State* L) { 
    lua_callback = luaL_ref(L, LUA_REGISTRYINDEX); 
    return 0; 
} 
static int testnotify(lua_State* L) { 
    lua_rawgeti(L, LUA_REGISTRYINDEX, lua_callback); 
    lua_call(L, 0, 0); 
    return 0; 
} 
static int testenv(lua_State* L) { 
    lua_getglobal(L, "defcallback"); 
    lua_call(L, 0, 0); 
    return 0; 
} 

static const luaL_Reg cblib[] = { 
    {"setnotify", setnotify}, 
    {"testnotify", testnotify}, 
    {"testenv", testenv}, 
    {NULL, NULL} 
}; 

int luaopen_cb(lua_State* L) { 
    luaL_register(L, "cb", cblib); 
    return 1; 
}

對比總結

維度註冊表引用全局環境查找
靈活性高(動態註冊任意函數)低(固定全局名)
命名空間污染無需佔用全局名
多回調支持易擴展(多索引)需約定多名字
適用場景通用庫、插件系統簡單腳本、快速原型

最佳實踐建議

  • 優先使用註冊表模式,解耦 C 與 Lua 命名空間。
  • 若用全局模式,Lua 端務必封裝一層隔離業務邏輯。
  • 注意 luaL_ref 返回 LUA_REFNIL 表示無效引用,調用前需判空。
  • 回調中若報錯,建議用 lua_pcall 保護調用棧。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved