该篇文章主要结合tolua.c 源码,逐行逐句分析ToLua中Wrap文件的运作原理。 开门见山,Tolua懂的都懂,这里就不赘述了。 在Tolua生成的Wrap文件中,经常遇见如此写法。 就很神奇的可以使用Lua来调用这些C#类的方法了。 首先BeginStaticLibs最终会走到这条语句上来: 接着先把尾给收掉,EndStaticLibs最后会来到tolua.c这边的 tolua_endstaticclass 方法,该方法最终会将栈顶元素弹出并将其设置为 – 2位置的元表 重点来了,C#方法的注册 tolua.c文件中tolua_function对传入进的函数进行了绑定。 C函数只要满足lua_CFunction的样子就可以被lua所使用。 此时,lua_State栈中的表现是这样的 最终在 到此,Tolua Wrap文件如何向Lua中注册C#方法的过程就完毕了。实际上我们会发现,一个C#方法的指针其实被封装了两层: 当我们在lua中调用注册的方法时,实际上是在调用最外层的CClosure结构体,它其中的方法是 实际上压入函数的过程就是形成闭包的过程,在lua中函数是以闭包的形式被保存的 void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); Pushes a new C closure onto the stack. When a C function is created, it is possible to associate some values with it, thus creating a C closure (see §3.4); these values are then accessible to the function whenever it is called. To associate values with a C function, first these values should be pushed onto the stack (when there are multiple values, the first value is pushed first). Then lua_pushcclosure:生成闭包,将函数存放在闭包结构体中,并将栈顶n个元素一同压入闭包内的栈 . 嗨,我是作者Vin129,逐儿时之梦正在游戏制作的技术海洋中漂泊。知道的越多,不知道的也越多。希望我的文章对你有所帮助:)
阅前提示
适合人群:lua使用人群
阅读方式:浏览
扩展阅读:Lua C语言API
Tolua
有关Tolua介绍和使用的文章很多,例如:点击查看Wrap
// XXXWrap.cs L.BeginStaticLibs("XXX"); L.RegFunction("Log", Log); L.EndStaticLibs();
接下来作者便深入其中,逐一分析这三句话究竟做了些什么。
BeginStaticLibs
LuaDLL.tolua_beginstaticclass(L, name);
这语句会执行tolua dll 的C语言对应方法,tolua_beginstaticclass ,该方法 最终会在lua_State栈顶生成一个名为name的table/* tolua.c */ LUALIB_API void tolua_beginstaticclass(lua_State *L, const char *name) { lua_pushstring(L, name); /* 将name 压入栈中,即 XXX */ lua_newtable(L);/* 创建一个table 压入栈中*/ _addtoloaded(L); lua_pushvalue(L, -1); /* 这里将栈顶表复制了一份压入栈中 即top [XXX(table),XXX(emptytable)] bottom */ /* 以上操作相当于生成了名为name的table :XXX = {} */ /* 以下操作抽象理解 */ /* XXX["userdata"] = &tag */ lua_pushlightuserdata(L, &tag); lua_pushnumber(L, 1); lua_rawset(L, -3); /* XXX[".name"] = XXX */ lua_pushstring(L, ".name"); _pushfullname(L, -4); lua_rawset(L, -3); /* XXX["__index"] = static_index_event */ lua_pushstring(L, "__index"); lua_pushcfunction(L, static_index_event); lua_rawset(L, -3); /* XXX["__newindex"] = static_newindex_event */ lua_pushstring(L, "__newindex"); lua_pushcfunction(L, static_newindex_event); lua_rawset(L, -3); }
L.BeginStaticLibs("XXX");
这里最终会在lua_State栈顶会被压入一个名为XXX的table
栈顶
XXX(table)
XXX(emptytable)
栈底
EndStaticLibs
/* tolua.c */ LUALIB_API void tolua_endstaticclass(lua_State *L) { lua_setmetatable(L, -2); lua_rawset(L, -3); }
L.EndStaticLibs();
//结束该table,弹出栈顶元素,将其设置为XXX(emptytable)的元表
like:top(栈顶) [XXX(metatable)] bottom(栈底)
栈顶
XXX(metatable)
栈底
RegFunction
RegFunction先是将要注册的方法转换成了供平台使用的指针,传递到C中生成可以供lua使用的LuaCSFunction函数。// LuaState.cs public void RegFunction(string name, LuaCSFunction func) { IntPtr fn = Marshal.GetFunctionPointerForDelegate(func); LuaDLL.tolua_function(L, name, fn); }
/* tolua.c */ LUALIB_API void tolua_function(lua_State *L, const char *name, lua_CFunction fn) { lua_pushstring(L, name); tolua_pushcfunction(L, fn); lua_rawset(L, -3); }
栈: [CClosure(f:tolua_closure,upvalue[0(false),CClosure(f:fn)]),name,XXX(table)] 下面内容会重点分析这部分究竟做了些什么
/* tolua.c */ LUA_API int tolua_pushcfunction(lua_State *L, lua_CFunction fn) { lua_pushboolean(L, 0); lua_pushcfunction(L, fn); lua_pushcclosure(L, tolua_closure, 2); return 0; }
栈顶
CClosure(f:tolua_closure,upvalue[0(false),CClosure(f:fn)])
name:Log
XXX(table)
栈底
lua_rawset(L, -3)
的作用下,变为了这样
栈顶
XXX : {Log = CClosure …}
栈底
lua_pushcfunction(L, fn)
时 将fn封装进了CClosure中。lua_pushcclosure(L, tolua_closure, 2)
时将封装了fn的CClosure再一次封装进了新的CClosure中。tolua_closure
,而我们的C#方法指针fn作为该结构体栈中的值被存放着(upvalue)static int tolua_closure(lua_State *L) { /* 获取到我们所注册的C#方法指针 */ lua_CFunction fn = (lua_CFunction)lua_tocfunction(L, lua_upvalueindex(2)); /* 运行 ,因为lua跨语言的数据交互都借助栈来完成,所以运行结果都是通过获取栈中元素来获得 */ int r = fn(L); if (lua_toboolean(L, lua_upvalueindex(1))) { lua_pushboolean(L, 0); lua_replace(L, lua_upvalueindex(1)); return lua_error(L); } return r; }
lua_pushcfunction
/* lua.h */ #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) /* 宏 压入闭包方法 n为0 */
lua_pushcclosure
lua_pushcclosure
is called to create and push the C function onto the stack, with the argument n
telling how many values should be associated with the function. lua_pushcclosure
also pops these values from the stack.
官方地址/* lua.h */ LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
/* lapi.c */ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { lua_lock(L); if (n == 0) { setfvalue(L->top, fn); api_incr_top(L); } else { CClosure *cl; api_checknelems(L, n); api_check(L, n <= MAXUPVAL, "upvalue index too large"); /* #define MAXUPVAL 255 */ cl = luaF_newCclosure(L, n);/* 创建了闭包结构体 */ cl->f = fn; L->top -= n; /* 将栈顶n个元素移除并压入闭包的栈中 upvalue */ while (n--) { setobj2n(L, &cl->upvalue[n], L->top + n); /* does not need barrier because closure is white */ } setclCvalue(L, L->top, cl); api_incr_top(L); luaC_checkGC(L); } lua_unlock(L); }
typedef struct CClosure { ClosureHeader; lua_CFunction f; TValue upvalue[1]; /* list of upvalues */ } CClosure;
.
.
.
.
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算