C模塊回調Lua函數的兩種方法 lua和C通過虛擬棧這種交互方式簡單而又可靠,缺點就是C做棧平衡稍微會多寫一點代碼。 今天分享學到的C模塊回調Lua函數的兩種方法,都是炒冷飯,大俠勿噴。 1. C保存函數對象 C模塊可以通過注冊表保存Lua裡面的對象,等適當時候取出再調用即可。 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); } luaL_ref把棧頂的值取出,放到指定的tabel中,然後返回一個索引(目測是數組的index)。 lua_rawgeti把之前保存的function對象取出,再由lua_call調用。 function callback( ) print "Callback" end cb.setnotify(callback) cb.testnotify() 2. C訪問Lua全局環境 第二種方法更簡便,C直接調用Lua中的函數,就像Lua調用C一樣 static int testenv(lua_State *L) { lua_getglobal(L, "defcallback"); lua_call(L, 0, 0); } 該方法的缺點就是如果C模塊獨立編寫,方法名就不太靈活。 用這種方法一般會在Lua端再封裝一層,以隔離全局環境。 3. 完整例子 cb.c #include <stdio.h> #include <stdlib.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); } static int testenv(lua_State *L) { lua_getglobal(L, "defcallback"); lua_call(L, 0, 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; } test.lua require("cb") function callback( ) print "Callback" end function defcallback() print "Predef callback" end cb.setnotify(callback) cb.testnotify() print "Done" cb.testenv()