LUA 源码浅析

这个文章是导航类,暂时先写个开头,后续慢慢补充

Tips:LUA调用C语言接口

  • 需求:C语言编写接口,导出给LUA调用
  • C接口形式:typedef int (lua_CFunction)(lua_State L)
  • 举例:int add(lua_State* L),即返回值需为int类型,参数只有一个且为lua_State指针类型
  • lua_State:L为LUA调用C接口时提供的指针,通过L的类接口/成员变量可访问LUA相关数据
  • 输入参数获取方式:通过L指针导出方法,如luaL_checknumber(L,1);检查参数合法性并返回第一个输入参数(从左到右)
  • 输出参数传递方式:通过压栈传递输出值,如:lua_pushnumber(L,op1 + op2),且压了几个参数入栈就要return几,使LUA可正确的平衡栈

LUA源码阅读笔记(ver: 5.3.4)

从一个函数开始了解LUA的实现机制,一些较深的内容会出独立篇章,如:TValue结构…
源码阅读先从数学计算库开始

  1. lmathlib.c
    用C语言实现了一些数学计算类函数接口,供LUA调用,解析一个ABS函数,理解LUA的数据接口和使用方式,如下:
// 求绝对值的导出函数
static int math_abs (lua_State *L) {	//符合导出接口形式约定
  if (lua_isinteger(L, 1)) {
    lua_Integer n = lua_tointeger(L, 1);
    if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n);
    lua_pushinteger(L, n);
  }
  else
    lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1)));
  return 1;
}

// 其中调用了lua_isinteger判断输入参数类型,其函数实现为:
LUA_API int lua_isinteger (lua_State *L, int idx) {
  const TValue *o = index2value(L, idx);
  return ttisinteger(o);
}

// 其中ttisinterger(0)为宏定义,结合参数的展开过程为:
#define ttisinteger(o)		checktag((o), LUA_VNUMINT)
#define ttisinteger(o)		checktag((o), makevariant(LUA_TNUMBER, 0))	//其中LUA_TNUMBER为3
#define ttisinteger(o)		checktag(o, 3)
#define ttisinteger(o)		o->tt_ == 3		//其中o的类型为TValue

其中基本可以猜测到TValue结构中存在一个成员变量tt_表示变量的类型,其中3是int的枚举值,有关TValue详细解析见:LUA TValue结构.(建议先看玩这篇再继续)

回到lua_isinteger函数中来,发现其中TValue类型的o变量是由函数index2value调用返回的,查看其实现如下:

static TValue *index2value (lua_State *L, int idx) {
  CallInfo *ci = L->ci;
  if (idx > 0) {
    StkId o = ci->func + idx;
    api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index");
    if (o >= L->top) return &G(L)->nilvalue;	//超出栈空间返回nil空
    else return s2v(o);
  }
  else{
  	...//ID<=0的部分暂时不看,可理解为错误调用
  }
}

//api_check为宏定义,结合参数的展开过程为:
#define api_check(l,e,msg)	luai_apicheck(l,(e) && msg)
#define api_check(l,e,msg)	luai_apicheck(L,(1 <= L->ci->top - (ci->func + 1) && "unacceptable index")
#define api_check(l,e,msg)	luai_apicheck(L,(1 <= 栈空间所最大支持的参数个数) && "unacceptable index")	
#define api_check(l,e,msg)	(L, lua_assert(1)) / (L, lua_assert(0))

/* convert a 'StackValue' to a 'TValue' */
#define s2v(o)	(&(o)->val)

基本可以猜测到ci->func为栈顶指针,通过+idx的方式找到输入参数的地址,在通过s2v得到TValue
api_check负责检查请求访问的输入参数是否超出了栈空间,防止数据的非法访问
其中CallInfo结构,StkId结构解析见链接:LUA CallInfo结构,StkId结构解析.(建议先看玩这篇再继续)

回到math_abs 函数中来,其中取参数是调用了lua_tointeger函数

lua_Integer n = lua_tointeger(L, 1);#define lua_tointeger(L,i)	lua_tointegerx(L,(i),NULL)
LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) {
  lua_Integer res = 0;
  const TValue *o = index2value(L, idx);
  int isnum = tointeger(o, &res);
  if (pisnum)
    *pisnum = isnum;
  return res;
}lua_tointeger(L, 1) == lua_tointegerx (L, 1, NULL)
index2value函数在上面已经解析过,作用是通过序列号将栈结构中指定ID的数据取出,这里取出第一个参数
这里tointeger(o, &res) 等价于 (o)->tt_ == 3 ? (*(&res) = (((o)->value_).i), 1) : luaV_tointeger(o,&res,F2Ieq))
这里会进行tt_是否为3的判断,是因为此版本中LUA将intfloat值都存放于lua_Integer中,因此需要在此做出区分

  1. lstrlib.c
  2. lapi.c
  3. lobject.h
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值