1.lua的数据类型
#define LUA_TNONE (-1) //无类型
#define LUA_TNIL 0 //空类型
#define LUA_TBOOLEAN 1 //bool
#define LUA_TLIGHTUSERDATA 2 //指针(需要关注内存释放)
#define LUA_TNUMBER 3 //数据
#define LUA_TSTRING 4 //string
#define LUA_TTABLE 5 //表
#define LUA_TFUNCTION 6 //函数
#define LUA_TUSERDATA 7 //指针(不需要关注内存释放)
#define LUA_TTHREAD 8 //lua虚拟机、协程
2.lua栈
2.1 栈底、栈顶和当前栈顶
struct lua_State {
...
StkId top; //当前栈顶,指向一个未使用的位置
...
StkId stack_last; //栈顶
StkId stack; //栈底,栈基址
...
};
2.2栈的元素和初始化
static void stack_init (lua_State *L1, lua_State *L) {
...
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); //申请BASIC_STACK_SIZE + EXTRA_STACK个StackValue大小的内存
L1->tbclist = L1->stack;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) //clean
setnilvalue(s2v(L1->stack + i)); /* erase new stack */
L1->top = L1->stack;
L1->stack_last = L1->stack + BASIC_STACK_SIZE;
...
}
这个函数调用的时候L1和L是同一个东西
static void f_luaopen (lua_State *L, void *ud) {
...
stack_init(L, L); /* init stack */
...
}
StackValue是这个栈的元素,这个结构的定义如下
#define TValuefields Value value_; lu_byte tt_
typedef struct TValue {
TValuefields;
} TValue;
typedef union StackValue {
TValue val;
struct {
TValuefields;
unsigned short delta;
} tbclist;
} StackValue;
typedef StackValue *StkId;
#define s2v(o) (&(o)->val)
可以看到StkId
是StackValue
的指针类型,我们的栈指针都是这个类型。StackValue
本质是一个TValue
类型(可以使用s2v这个宏转为TValue),也就是说这个栈可以存在lua的所有类型的数据
有关Tvalue
的实现之前写过一篇,这里不再继续写 https://blog.csdn.net/qq_41252394/article/details/117868916
3.lua中操作栈的api
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vpg7XUXS-1630855807694)(./栈.png)]
栈索引
3.1 栈当前大小设置
LUA_API int (lua_gettop) (lua_State *L); //获取当前的栈大小
LUA_API void (lua_settop) (lua_State *L, int idx); //设置当前的栈大小
LUA_API int lua_gettop (lua_State *L) {
return cast_int(L->top - (L->ci->func + 1)); //当前栈顶 - 当前函数基地址
}
LUA_API void lua_settop (lua_State *L, int idx) {
CallInfo *ci;
StkId func, newtop;
ptrdiff_t diff; /* difference for new top */
lua_lock(L);
ci = L->ci;
func = ci->func;
if (idx >= 0) {
api_check(L, idx <= ci->top - (func + 1), "new top too large");
diff = ((func + 1) + idx) - L->top; //计算相对位置
for (; diff > 0; diff--)
setnilvalue(s2v(L->top++)); //如果大于当前栈顶,把多余值置空
}
else {
api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
diff = idx + 1; //计算相对位置,-1是栈顶
}
api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
newtop = L->top + diff; //计算新的栈顶位置
if (diff < 0 && L->tbclist >= newtop) { //栈基址大于新的栈顶位置
lua_assert(hastocloseCfunc(ci->nresults));
luaF_close(L, newtop, CLOSEKTOP, 0);
}
L->top = newtop; //设置新的栈顶位置
lua_unlock(L);
}
3.2 在栈中取值
idx的各个范围
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AuLZEU8x-1630855807697)(./index_set.png)]
idx > 0:栈的正常索引
LUA_REGISTRYINDEX< idx <= 0:栈的正常索引
idx = LUA_REGISTRYINDEX: G(L)->l_registry
idx < LUA_REGISTRYINDEX:访问的是当前函数的upval表
#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX)
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; //如果这个值的地址大于当前栈顶,直接返回空值
else return s2v(o); //把值转为TValue
}
else if (!ispseudo(idx)) { //LUA_REGISTRYINDEX< idx <= 0 ,正常的负数索引
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
return s2v(L->top + idx);
}
else if (idx == LUA_REGISTRYINDEX) //idx = LUA_REGISTRYINDEX
return &G(L)->l_registry;
else { //idx < LUA_REGISTRYINDEX
idx = LUA_REGISTRYINDEX - idx; //>1
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
if (ttislcf(s2v(ci->func))) //如果当前函数是c函数,返回空
return &G(L)->nilvalue;
else { //返回idx-1的upval表
CClosure *func = clCvalue(s2v(ci->func));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue;
}
}
}
3.3 压栈
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
"stack overflow");}
LUA_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L);
setobj2s(L, L->top, index2value(L, idx)); //获取idx索引的值,写入当前栈顶
api_incr_top(L); //抬栈
lua_unlock(L);
}
栈拷贝
LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
TValue *fr, *to;
lua_lock(L);
fr = index2value(L, fromidx);
to = index2value(L, toidx);
api_check(L, isvalid(L, to), "invalid index");
setobj(L, to, fr); //拷贝
if (isupvalue(toidx)) /* function upvalue? */
luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr);
/* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */
lua_unlock(L);
}
各个类型版本的压栈
LUA_API void (lua_pushnil) (lua_State *L);
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
va_list argp);
LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
LUA_API void (lua_pushboolean) (lua_State *L, int b);
LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
LUA_API int (lua_pushthread) (lua_State *L);
这些函数都是类似的逻辑
- 设置值
- 抬栈
如:
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L);
setfltvalue(s2v(L->top), n); //写值
api_incr_top(L); //抬栈
lua_unlock(L);
}
3.4 类型相关的api
//类型判断
LUA_API int (lua_isnumber) (lua_State *L, int idx);
LUA_API int (lua_isstring) (lua_State *L, int idx);
LUA_API int (lua_iscfunction) (lua_State *L, int idx);
LUA_API int (lua_isinteger) (lua_State *L, int idx);
LUA_API int (lua_isuserdata) (lua_State *L, int idx);
LUA_API int (lua_type) (lua_State *L, int idx); //返回类型
LUA_API const char *(lua_typename) (lua_State *L, int tp); //返回类型名
//类型转换
LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
LUA_API int (lua_toboolean) (lua_State *L, int idx);
LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
LUA_API void *(lua_touserdata) (lua_State *L, int idx);
LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
LUA_API const void *(lua_topointer) (lua_State *L, int idx);
LUA_API lua_Unsigned (lua_rawlen) (lua_State *L, int idx); //取长度 #
这些代码相对简单不再展开
3.5 比较api
LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op);
LUA_API int lua_rawequal (lua_State *L, int index1, int index2) {
const TValue *o1 = index2value(L, index1); //取值
const TValue *o2 = index2value(L, index2); //取值
return (isvalid(L, o1) && isvalid(L, o2)) ? luaV_rawequalobj(o1, o2) : 0; //如果都不为空,则开始比较
}
#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)
int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
const TValue *tm;
if (ttypetag(t1) != ttypetag(t2)) { //判断两个值的类型
if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER) //判断两个值具体类型(int double)
return 0; /* only numbers can be equal with different variants */
else { //两个值一个是int,一个是double,转成int比较
lua_Integer i1, i2;
return (luaV_tointegerns(t1, &i1, F2Ieq) &&
luaV_tointegerns(t2, &i2, F2Ieq) &&
i1 == i2);
}
}
//其他类型的比较
switch (ttypetag(t1)) {
case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: return 1;
case LUA_VNUMINT: return (ivalue(t1) == ivalue(t2));
case LUA_VNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2));
case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
case LUA_VLCF: return fvalue(t1) == fvalue(t2);
case LUA_VSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2));
case LUA_VLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2));
case LUA_VUSERDATA: {
if (uvalue(t1) == uvalue(t2)) return 1;
else if (L == NULL) return 0;
tm = fasttm(L, uvalue(t1)->metatable, TM_EQ);
if (tm == NULL)
tm = fasttm(L, uvalue(t2)->metatable, TM_EQ);
break; /* will try TM */
}
case LUA_VTABLE: {
if (hvalue(t1) == hvalue(t2)) return 1;
else if (L == NULL) return 0;
tm = fasttm(L, hvalue(t1)->metatable, TM_EQ);
if (tm == NULL)
tm = fasttm(L, hvalue(t2)->metatable, TM_EQ);
break; /* will try TM */
}
default:
return gcvalue(t1) == gcvalue(t2);
}
if (tm == NULL) /* no TM? */
return 0; /* objects are different */
else {
luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */
return !l_isfalse(s2v(L->top));
}
}
3.6 全局信息表
LUA_API int (lua_getglobal) (lua_State *L, const char *name); //获取全局信息表,返回在栈中,函数返回值为该数据的类型
LUA_API void (lua_setglobal) (lua_State *L, const char *name); //设置全局信息表
全局信息表的位置
#define LUA_RIDX_GLOBALS 2
#define getGtable(L) \
(&hvalue(&G(L)->l_registry)->array[LUA_RIDX_GLOBALS - 1])
获取全局信息表
#define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (slot = f(hvalue(t), k), /* else, do raw access */ \
!isempty(slot))) /* result not empty? */
static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) { //获取key为k的值,输出到slot
setobj2s(L, L->top, slot); //如果slot不为空,把值压入栈中
api_incr_top(L);
}
else {
setsvalue2s(L, L->top, str);
api_incr_top(L);
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
}
lua_unlock(L);
return ttype(s2v(L->top - 1)); //返回压入值的类型
}
//key为name,该值对应的val压入栈中
LUA_API int lua_getglobal (lua_State *L, const char *name) {
const TValue *G;
lua_lock(L);
G = getGtable(L); //获取全局信息表
return auxgetstr(L, G, name);
}
设置全局信息表
#define luaV_finishfastset(L,t,slot,v) \
{ setobj2t(L, cast(TValue *,slot), v); \
luaC_barrierback(L, gcvalue(t), v); }
static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) { //获取key为k的值,输出到slot
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); //设置这个key的值
L->top--; /* pop value */
}
else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot);
L->top -= 2; /* pop value and key */
}
lua_unlock(L); /* lock done by caller */
}
//key为name,val是压栈的值
LUA_API void lua_setglobal (lua_State *L, const char *name) {
const TValue *G;
lua_lock(L); /* unlock done in 'auxsetstr' */
G = getGtable(L);
auxsetstr(L, G, name);
}
3.7 表操作
3.7.1 创建表
//创建表,压入栈中
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
3.7.2 表的获取和修改
//获取表数据
LUA_API int (lua_gettable) (lua_State *L, int idx);
LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);
LUA_API int (lua_rawget) (lua_State *L, int idx);
LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
//设置表数据
LUA_API void (lua_settable) (lua_State *L, int idx);
LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n);
LUA_API void (lua_rawset) (lua_State *L, int idx);
LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n);
LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p);
//idx为表在栈中的索引,key为刚压入栈的值,获取的值覆盖key的值
LUA_API int lua_gettable (lua_State *L, int idx) {
const TValue *slot;
TValue *t;
lua_lock(L);
t = index2value(L, idx); //获取表的位置
if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) { //获取key为L->top - 1的值,赋值到slot
setobj2s(L, L->top - 1, slot); //覆盖key的值
}
else
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
lua_unlock(L);
return ttype(s2v(L->top - 1));
}
//idx为表在栈中的索引,key第一次压入的值,value为第二次压入的值.把对应的key->val压入表中
LUA_API void lua_settable (lua_State *L, int idx) {
TValue *t;
const TValue *slot;
lua_lock(L);
api_checknelems(L, 2);
t = index2value(L, idx); //获取表的位置
if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) { //获取key为L->top - 2的值,赋值到slot
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); //设置这个key的值
}
else
luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot);
L->top -= 2; /* pop index and value */
lua_unlock(L);
}
这组api和上面两个类似,只是key不用再压栈换成了函数的参数
LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);
LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n);
3.7.3 元表
元表是table类型的一个子表
typedef struct Table {
CommonHeader;
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
lu_byte lsizenode; /* log2 of size of 'node' array */
unsigned int alimit; /* "limit" of 'array' array */
TValue *array; /* array part */
Node *node;
Node *lastfree; /* any free position is before this position */
struct Table *metatable; //元表
GCObject *gclist;
} Table;
3.7.3.1 创建元表
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
//返回元表压入栈中
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
if (luaL_getmetatable(L, tname) != LUA_TNIL) //检查名称是否被使用
return 0; /* leave previous value on top, but return 0 */
lua_pop(L, 1); //弹出栈中的nil值
lua_createtable(L, 0, 2); //创建table
lua_pushstring(L, tname);
lua_setfield(L, -2, "__name"); //metatable[__name] = tname
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, tname); //registry.name = metatable
return 1;
}
3.7.3.2 设置元表
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) {
luaL_getmetatable(L, tname); //获取元表
lua_setmetatable(L, -2);
}
LUA_API int lua_setmetatable (lua_State *L, int objindex) {
TValue *obj;
Table *mt;
lua_lock(L);
api_checknelems(L, 1);
obj = index2value(L, objindex); //获取设置元表的对象
if (ttisnil(s2v(L->top - 1))) //如果元表为空,直接设置为NULL
mt = NULL;
else {
api_check(L, ttistable(s2v(L->top - 1)), "table expected");
mt = hvalue(s2v(L->top - 1)); //如果不为空,TValue转成Table
}
switch (ttype(obj)) {
case LUA_TTABLE: {
hvalue(obj)->metatable = mt; //设置元表
if (mt) {
luaC_objbarrier(L, gcvalue(obj), mt);
luaC_checkfinalizer(L, gcvalue(obj), mt);
}
break;
}
case LUA_TUSERDATA: {
uvalue(obj)->metatable = mt;
if (mt) {
luaC_objbarrier(L, uvalue(obj), mt);
luaC_checkfinalizer(L, gcvalue(obj), mt);
}
break;
}
default: {
G(L)->mt[ttype(obj)] = mt;
break;
}
}
L->top--;
lua_unlock(L);
return 1;
}
4.lua和c交互
4.1 lua文件解析和函数调用
#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
luaL_loadfile是lua的文件解析函数返回一个Closure对象压入栈中
lua_pcall是函数执行函数负责执行Closure对象函数对象
4.2 全局变量的获取
lua脚本中的常用的类型 number、string、table、function。
获取全局变量的函数只要使用 lua_getglobal
首先我们使用lua api去执行这个脚本,执行完lua脚本。脚本执行完后lua状态机的一些信息将会被修改。
如全局变量表G(L)->l_registry 将会加入这些全局变量的符号。之后使用lua_getglobal获取这些信息
反之我们可以使用lua api去改变lua状态机,然后再去执行lua脚本。这样就可以在c中设置一下全局变量给lua
4.2.1 脚本执行
int main(int argc,char *argv[])
{
//创建lua状态机
lua_State *ls = luaL_newstate();
//编译并且执行lua脚本
int ret = luaL_loadfile(ls,"../lua/test.lua") || lua_pcall(ls,0,0,0);
if (ret) {
fprintf(stderr,"%s\n",lua_tostring(ls,-1));
lua_pop(ls,1);
return -1;
}
//释放状态机资源
lua_close(ls);
return 0;
}
4.2.2 lua_getglobal的使用
width = 10
height = 30
str = "hello lua"
tab = {a=12,b=14,c=30}
function number_max(a,b)
if a > b then
return a
end
return b
end
获取number
//获取int值
int get_int_val(lua_State *L,const char *name,lua_Integer *val)
{
lua_getglobal(L,name);
if (!lua_isinteger(L,-1)) {
return -1;
}
*val = lua_tointeger(L,-1);
lua_pop(L,1);
return 0;
}
int main(int argc,char *argv[])
{
//创建lua状态机
lua_State *ls = luaL_newstate();
//编译并且执行lua脚本
int ret = luaL_loadfile(ls,"../lua/test.lua") || lua_pcall(ls,0,0,0);
if (ret) {
fprintf(stderr,"%s\n",lua_tostring(ls,-1));
lua_pop(ls,1);
return -1;
}
lua_Integer width = 0;
get_int_val(ls,"width",&width);
lua_Integer height = 0;
get_int_val(ls,"height",&height);
printf("width = %lld\nheight = %lld\n",width,height);
//释放状态机资源
lua_close(ls);
return 0;
}
获取string
lua_getglobal(ls,"str");
const char *str = lua_tostring(ls,-1);
lua_pop(ls,1);
printf("str = %s\n",str);
获取table
lua_getglobal(ls,"tab");
lua_getfield(ls,-1,"a");
lua_Integer a = lua_tointeger(ls,-1);
lua_pop(ls,1);
lua_getfield(ls,-1,"b");
lua_Integer b = lua_tointeger(ls,-1);
lua_pop(ls,1);
printf("a = %lld\nb = %lld\n",a,b);
lua_pop(ls,1);
也可以使用原生table的数据结构的api
lua_getglobal(ls,"tab");
Table *table = hvalue(s2v(ls->top-1));
const TValue *pa = luaH_getstr(table,luaS_newliteral(ls,"a"));
const TValue *pb = luaH_getstr(table,luaS_newliteral(ls,"b"));
lua_pop(ls,1);
printf("a = %lld\nb = %lld\n",ivalue(pa),ivalue(pb));
函数
lua_getglobal(ls,"number_max");
//参数从左到右压栈
lua_pushinteger(ls,20);
lua_pushinteger(ls,99);
//函数执行,两个参数,一个返回值
lua_call(ls,2,1);
//函数执行完,函数返回值压栈
lua_Integer max_ret = lua_tointeger(ls,-1);
printf("call function return %lld\n",max_ret);
lua_pop(ls,1);
4.2.3 lua_setglobal的使用
print("width = "..width)
print("height = "..height)
print("str = "..str)
print(tab)
for k,v in pairs(tab) do
print(k,v)
end
print("max = "..number_max(20,40))
设置number
int main_set(int argc,char *argv[])
{
lua_State *ls = luaL_newstate();
luaL_openlibs(ls);
lua_pushinteger(ls,480);
lua_setglobal(ls,"width");
lua_pushinteger(ls,1080);
lua_setglobal(ls,"height");
int ret = luaL_loadfile(ls,"../lua/lua_api_set.lua") || lua_pcall(ls,0,0,0);
if (ret) {
fprintf(stderr,"%s\n",lua_tostring(ls,-1)); //
lua_pop(ls,1);
return -1;
}
return 0;
}
设置string
lua_pushstring(ls,"hello lua");
lua_setglobal(ls,"str")
设置table
lua_newtable(ls); //创建table,创建完table会压入栈中
lua_pushnumber(ls,30);
lua_setfield(ls,-2,"a"); //tab["a"] = 30
lua_pushnumber(ls,99);
lua_setfield(ls,-2,"b");
lua_setglobal(ls,"tab");
函数
int lua_max(lua_State *ls)
{
lua_Integer a = luaL_checkinteger(ls,-2);
lua_Integer b = luaL_checkinteger(ls,-1);
lua_pushinteger(ls,(a > b ? a : b));
return 1;
}
lua_pushcfunction(ls,lua_max);
lua_setglobal(ls,"number_max");
lua函数的格式
typedef int (*lua_CFunction) (lua_State *L);
- 函数的返回值是lua函数返回的参数个数
- lua函数调用时的参数,是通过压栈的方式传入c函数中的
- lua函数的返回值是c函数压栈传出的
- 可以通过当前函数的栈顶来确认传入c函数的参数个数 lua_gettop