Lua自带的模块并不多,好处就是Lua足够的小,毕竟它的设计目标是定位成一个嵌入式的轻量级语言的.

相关的函数index2adr

static TValue *index2adr (lua_State *L, int idx) {
if (idx > 0) {
TValue *o = L->base + (idx - 1);
api_check(L, idx <= L->ci->top - L->base);
if (o >= L->top) return cast(TValue *, luaO_nilobject);
else return o;
}
else if (idx > LUA_REGISTRYINDEX) {
api_check(L, idx != 0 && -idx <= L->top - L->base);
return L->top + idx;
}
else switch (idx) { /* pseudo-indices */
case LUA_REGISTRYINDEX: return registry(L);
case LUA_ENVIRONINDEX: {
Closure *func = curr_func(L);
sethvalue(L, &L->env, func->c.env);
return &L->env;
}
case LUA_GLOBALSINDEX: return gt(L);
default: {
Closure *func = curr_func(L);
idx = LUA_GLOBALSINDEX - idx;
return (idx <= func->c.nupvalues)
? &func->c.upvalue[idx-1]
: cast(TValue *, luaO_nilobject);
}
}
}

一个Lua函数栈由两个指针base和top来指定,base指向函数栈底,top则指向栈顶.

回到index2addr函数中,几种情况:

  1. 如果索引为正,则从函数栈底为起始位置向上查找数据
  2. 如果索引为负,则从函数栈顶为起始位置向下查找数据
  3. 紧跟着是几种特殊的索引值,都定义了非常大的数据,由于Lua栈限定了函数的栈尺寸,所以不会有那么大的索引,大可放心使用.

索引值为LUA_REGISTRYINDEX时,则返回的是全局数据global_state的l_registry表;如果索引值为LUA_GLOBALSINDEX,则返回该Lua_State的l_gt表.

lua模块注册

Lua内部所有模块的注册都在linit.c的函数luaL_openlibs中提供.可以看到的是,它依次访问一个数组,数组中定义了每个模块的模块名及相应的模块注册函数,依次调用函数就完成了模块的注册.

static const luaL_Reg lualibs[] = {
{"", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_DBLIBNAME, luaopen_debug},
{NULL, NULL}
}; LUALIB_API void luaL_openlibs (lua_State *L) {
const luaL_Reg *lib = lualibs;
for (; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_pushstring(L, lib->name);
lua_call(L, 1, 0);
}
}

我没有详细的查看每个模块的注册函数,不过还是以最简单的例子来讲解,就是最常用的print函数.

由于这个函数没有前缀,因此的它所在的模块是”",也就是一个空字符串,因此它是在base模块中注册的,调用的注册函数是luaopen_base.

紧跟着继续看luaopen_base内部调用的第一个函数base_open:

static void base_open (lua_State *L) {
/* set global _G */
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setglobal(L, "_G");
/* open lib into global table */
luaL_register(L, "_G", base_funcs); // ....
}

首先来看最前面的两句:

  /* set global _G */
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setglobal(L, "_G");

这两句首先将LUA_GLOBALSINDEX对应的值压入栈中,其次调用”lua_setglobal(L, “_G”);”,这句代码的意思是在Lua_state的l_gt表中,当查找”_G”时,查找到的是索引值为LUA_GLOBALSINDEX的表.如果觉得有点绕,可以简单这个理解,在Lua中的G表,也就是全局表,满足这个等式”_G = _G["_G"]“,也就是这个叫”_G”的表,内部有一个key为”_G”的表是指向自己的.怀疑这个结论的,可以在Lua命令行中执行print(_G)和print(_G["_G"])看看输出结果是不是一致的.

Lua中要这么处理的理由是:为了让G表和处理其它表使用同样的机制.查找一个变量时,最终会一直查到G表中,这是很自然的事情;所以为了也能按照这个机制顺利的查找到自己,于是在G表中有一个同名成员指向自己.

好了,前面两句的作用已经分析完毕.其结果有两个:

  1. _G = _G["_G"]
  2. _G表的值压入函数栈中方便了下面的调用.

继续看下面的语句:

luaL_register(L, “_G”, base_funcs);

它最终会将base_funcs中的函数注册到G表中,但是里面还有些细节需要看看的.

LUALIB_API void luaI_openlib (lua_State *L, const char *libname,
const luaL_Reg *l, int nup) {
if (libname) {
int size = libsize(l);
/* check whether lib already exists */
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);
lua_getfield(L, -1, libname); /* get _LOADED[libname] */
if (!lua_istable(L, -1)) { /* not found? */
lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL)
luaL_error(L, "name conflict for module " LUA_QS, libname);
lua_pushvalue(L, -1);
lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */
}
lua_remove(L, -2); /* remove _LOADED table */
lua_insert(L, -(nup+1)); /* move library table to below upvalues */
} // ...
}

注册这些函数之前,首先会到l_registry表的成员_LOADED表中查找该库,如果不存在则再在G表中查找这个库,不存在则创建一个表.因此,不管是lua中内部的库或者是外部使用require引用的库,都会走这个流程并最终在G表和l_registry["_LOADED"]中存放该库的表.最后,再遍历传进来的函数指针数组,完成库函数的注册.

比如,注册os.print时,首先将print函数绑定在一个函数指针上,再去l_registry["_LOADED"]和G表中查询该名为”os”的库是否存在,不存在则创建一个表,即:

G["os"] = {}

紧跟着注册print函数,即: G["os"]["print"] = 待注册的函数指针.这样,在调用lua代码os.print(1)时,首先根据”os”到G表中查找对应的表,再在这个表中查找”print”成员得到函数指针,最后完成函数的调用.

注册外部模块

luaL_newlibtable 它仅仅是创建了一个table,然后把数组里的函数放进去而已

luaL_setfuncs它把数组l中的所有函数注册入栈顶的table,并给所有函数绑上nupupvalue

define luaL_newlibtable(L, l)

lua_createtble(L, 0, sizeof(l)/sizeof((l)[0]) - 1)

define luaL_newlib(L, l)

(luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)
LUALIB_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup){
luaL_checkversion(L);
luaL_checkstack(L, nup, "too_many_upvalue");
for(; l->name != NULL; i++){/* fill the table with given functions*/
int i;
for(i = 0; i < nup; i++)/copy upvalues to the top/
lua_pushvalue(L, -nup);
lua_pushclosure(L, l->func, nup);/closure with those upvalues/
lua_setfield(L, -(nup + 2), l->name);
}
lua_pop(L, nup);/remove upvalues/
}

最新文章

  1. asp.net 解决 &quot;回发或回调参数无效&quot; 一些常见解决方案
  2. Unity中游戏的声音管理
  3. distribution数据库过大问题
  4. 分布式算法系列——一致性Hash算法
  5. 【HDU 5105】Math Problem
  6. bzoj2801
  7. XSD标准架构-----&lt;xsd:element&gt; 元素详解
  8. 线程间操作无效 progressBar2线程不能被访问
  9. tomcat web项目部署方式
  10. 在sql中case子句的两种形式
  11. Python3-join()和split()
  12. Python fcntl 与 signal 模块使用
  13. 使用shell数据处理数据实例①-------手把手教学版
  14. MPI 环境配置,MPICH,VisualStudio
  15. Linux设备驱动之Ioctl控制
  16. selenium测试(Java)--学习总结
  17. Struts2中带参数的结果集
  18. js基本知识2
  19. elasticsearch的store属性 vs _source字段
  20. list_entry(ptr, type, member)——知道结构体内某一成员变量地址,求结构体地址

热门文章

  1. codeforces 741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(启发式合并)
  2. APP的案例分析
  3. ZooKeeper学习之路 (九)利用ZooKeeper搭建Hadoop的HA集群
  4. Python学习之路 (一)开发环境搭建
  5. linq to sql 分页技术
  6. 最易懂的layui分页
  7. (转)CentOS 7 —— /etc/rc.local 开机不执行 - 解决方法
  8. Linux内存调试工具初探-MEMWATCH(转)
  9. springboot activiti 整合项目框架源码 druid 数据库连接池 shiro 安全框架
  10. js动态生成水印