好久没有在网上留言了。。。
背景介绍
因为工作的需要,后台svr要能够动态修改更新,使用C当然没有问题,问题就在于修改源码后,需要重启服务。所以就想到在C里能够嵌入一种脚本,最好是和C无缝结合的。因此就想到使用到LUA,LUA的大名圈内人士应该早有耳闻,只不过一直没有机会接触。机缘巧合,有幸一见。
俗话说得好,耳闻不如一见。LUA使用起来还是很简单的,语法和普通的脚本语言相差不大,很容易上手。在实际项目的使用过程中,对LUA性能的体验也是感受尤深。这也是决定一探LUA源码的动力所在。因此,本笔记也只是针对LUA源码的相关记录,不会涉及到LUA使用上的一些问题。同时,也欢迎各位LUA爱好者批评指正笔记中的错误之处。废话不说了,切入正题。
(1)mathlib strlib
mathlib 和 strlib是lua的一个基本库,每个函数的实现都是在在基本库的基础上重新封装,举个例子
static int math_abs (lua_State *L) {
lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));
return 1;
}
调用基本库fabs()函数,将返回的结果压栈返回。那肯定有一个疑问,就是参数怎么传递进去的?是呀,参数怎么传递进去的,我现在也不知道,但是不要紧,先有个印象就行。
还要明白一点,外界不会直接调用math_abs(),为什么?static呀,如果不明白的,先修炼一下C的基本功吧,下面继续来猜测外面怎么调用这些函数。
static const luaL_Reg mathlib[] = {
{"abs", math_abs},
{"acos", math_acos},
{"asin", math_asin},
{"atan2", math_atan2},
{"atan", math_atan},
{"ceil", math_ceil},
{"cosh", math_cosh},
{"cos", math_cos},
{"deg", math_deg},
{"exp", math_exp},
{"floor", math_floor},
{"fmod", math_fmod},
{"frexp", math_frexp},
{"ldexp", math_ldexp},
{"log10", math_log10},
{"log", math_log},
{"max", math_max},
{"min", math_min},
{"modf", math_modf},
{"pow", math_pow},
{"rad", math_rad},
{"random", math_random},
{"randomseed", math_randomseed},
{"sinh", math_sinh},
{"sin", math_sin},
{"sqrt", math_sqrt},
{"tanh", math_tanh},
{"tan", math_tan},
{NULL, NULL}
};
上面这个结构体定义了内部函数名(或者是函数指针)与外部函数名之间的映射关系,比如要调用math_abs(),那实际使用的就是abs()来调用,目前,这还是猜测,是不是这样还有待验证。
那luaL_Reg 是啥,看如下声明:
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
就是一个名字,和一个函数指针,
typedef int (*lua_CFunction) (lua_State *L);
lua如何将这个映射注册进去呢,看下面的函数,这个是mathlib的外部唯一接口
LUALIB_API int luaopen_math (lua_State *L) {
luaL_register(L, LUA_MATHLIBNAME, mathlib);
lua_pushnumber(L, PI);
lua_setfield(L, -2, "pi");
lua_pushnumber(L, HUGE_VAL);
lua_setfield(L, -2, "huge");
#if defined(LUA_COMPAT_MOD)
lua_getfield(L, -1, "fmod");
lua_setfield(L, -2, "mod");
#endif
return 1;
}
大概的意思就是将mathlib这个luaL_Reg对象在L中注册登记,L是什么,L就是lua_State*!!!!!等于没说,但是目前的认知也就是这些,这是最准确的表述,不是吗?从名字上看,应该是一个状态机。想知道到底是什么,接着看代码。注册登记完了,将一些常量压栈。应该是设置一些环境变量,等等。
strlib和mathlib的结构差不多,
也是重新封装一大堆函数,然后通过一个唯一接口来注册所有的函数。实际使用的时候,也就是调用这个唯一的接口。调用完该接口,应该就可以在那个叫做lua_State*的L中使用这些基本库函数了。
到目前为止,很多还是不确定的,比如lua_State是什么,为什么基本库的注册登记,都要向针对这个L进行。L中到底维护的是什么信息,翻开lua_State的定义,一大堆数据,很多都不知道是什么。好吧,先不看这个,先继续看别的,但是要知道这个就是一个结构体就行,这个结构体里面肯定维护很多核心的东西。