简单描述下lua 虚拟栈的索引
假如存在十个元素 st[10]=st[-1]=st.top() st[1]=st[-10]=栈底部。
下面代码中用到的lua cAPI
- set_newlib()
void luaL_newlib (lua_State *L, const luaL_Reg l[]);
创建一个新表并在那里注册 列表中的函数。
它通过以下宏实现:
(luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
数组必须是实际数组, 不是指向它的指针。
void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
创建一个大小优化的新表 将所有条目存储在数组中(但实际上并不存储它们)。 它旨在与luaL_setfuncs结合使用(见luaL_newlib)。
它是作为宏实现的。 数组必须是实际数组, 不是指向它的指针。
-
lua_newuserdata()
void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue);
此函数在堆栈上创建并推送一个新的完整用户数据, 具有关联的 Lua 值,称为 , 加上一个与字节相关的原始内存块。 (可以使用函数 lua_setiuservalue 和 lua_getiuservalue 设置和读取用户值。
nuvalue
user values
size
该函数返回内存块的地址。 Lua 确保此地址在 相应的 UserData 是活动的(参见 §2.5)。 此外,如果用户数据被标记为最终确定(参见第 2.5.3 节), 其地址至少在调用其终结器之前有效。
-
luaL_checkudata()
void *luaL_checkudata (lua_State *L, int arg, const char *tname);
检查函数参数是否为 userdata 的类型(见luaL_newmetatable)和 返回 UserData 的内存块地址(参见 lua_touserdata)。
-
lua_createtable()
void lua_createtable (lua_State *L, int narr, int nrec);
创建一个新的空表并将其推送到堆栈上。 参数是表中元素数的提示 将作为一个序列; 参数是指示有多少其他元素 该表将有。 Lua 可能会使用这些提示为新表预分配内存。 当您提前知道时,这种预分配可能有助于性能 表格将包含多少个元素。 否则,您可以使用该函数lua_newtable。
-
luaL_newmetatable()
int luaL_newmetatable (lua_State *L, const char *tname);
如果注册表已具有项 , 返回 0。 否则 创建一个新表,用作 UserData 的元表, 将 pair 添加到这个新表中, 将 pair 添加到注册表中 , 并返回 1。
tname
__name = tname
[tname] = new table
在这两种情况下, 该函数将关联的最终值推送到堆栈上 在注册表中。
-
lua_setfield()
int lua_setmetatable (lua_State *L, int index);
从堆栈中弹出一个表或 nil,然后 将该值设置为给定索引处值的新元表。 现在始终为 1。
-
lua_pushvalue()
void lua_pushvalue (lua_State *L, int index);
在给定索引处推送元素的副本 到堆栈上。
-
lua_setuservalue()
int lua_setiuservalue (lua_State *L, int index, int n);
从堆栈中弹出一个值并将其设置为 与 给定索引处的完整用户数据。 如果 userdata 没有该值,则返回 0。
-
lua_getuservalue()
int lua_getiuservalue (lua_State *L, int index, int n);
将与 给定索引处的完整用户数据和 返回推送值的类型。
n
如果 userdata 没有该值, 按 nil 并返回 LUA_TNONE。
-
lua_seti()
void lua_seti (lua_State *L, int index, lua_Integer n);
是否等同于 , 其中 是给定索引处的值 and 是堆栈顶部的值。
t[n] = v
t
v
此函数从堆栈中弹出值。 与 Lua 一样,此函数可能会触发元方法 对于“NewIndex”事件(参见 §2.4)。
-
lua_geti()
int lua_geti (lua_State *L, int index, lua_Integer i);
将值 , 其中 是给定索引处的值。 与 Lua 一样,此函数可能会触发元方法 对于“index”事件(参见 §2.4)。
t[i]
t
返回推送值的类型。
-
lua_pop()
void lua_pop (lua_State *L, int n);
从堆栈中弹出元素。 它是在lua_settop上作为宏实现的
一 c 如何调用lua 代码
lua代码如下
-- 文件名 c.lua
function Init(... )
print("Init call")
-- body
end
function Start( ...)
print("start",...)
-- body
end
c代码如下
//文件名lua.c
#include<stdio.h>
#include<stdlib.h>
#include<lua.h>
#include<lauxlib.h>
#include<lualib.h>
static void
callFuncFromLua(lua_State*L,const char*funcName){
lua_getglobal(L,funcName);
lua_call(L,0,0);
}
static void
callFuncFromLuaWithParm(lua_State*L,const char*funcName,int parm){
lua_getglobal(L,funcName);
lua_pushnumber(L,parm);
lua_call(L,1,0);
}
int main(void){
const char* path="./c.lua";
//创建lua虚拟机
lua_State*L=luaL_newstate();
luaL_openlibs(L);
//编译并加载
if(luaL_dofile(L,path)!=LUA_OK){
const char* err=lua_tostring(L,-1);
fprintf(stderr,"err number:%s\n ",err);
}
int parm=666;
callFuncFromLua(L,"Init");
callFuncFromLuaWithParm(L,"Start",parm);
lua_close(L);
return 0;
}
二 lua 如何调用c代码
思路 :首先将c代码编译成动态库 ,动态库返回 lua表供lua使用
so.c
#include<stdio.h>
#include<stdlib.h>
#include<lua.h>
#include<lualib.h>
#include<lauxlib.h>
/**
* upvalue 上值
* c 闭包 多个上值 c函数
* gcc cso.c -o uv.so -fPIC --shared
*/
static int echo(lua_State*L){
lua_Integer cnt=lua_tointeger(L,lua_upvalueindex(1));//获取第一个上值
const char* str1=lua_tostring(L,lua_upvalueindex(2));
printf("上值元素为%s\n",str1);
cnt++;
const char*str=lua_tostring(L,-1);
printf("used [times=%lld] str:%s\n",cnt,str);
lua_pushinteger(L,cnt);
lua_replace(L,lua_upvalueindex(1));
return 0;
}
int luaopen_uv(lua_State*L){
lua_createtable(L,0,0); //创建一个新的空表压入虚拟栈
lua_pushinteger(L,0); //代表函数echo的上值(1)
lua_pushstring(L,"aron yang");//代表函数echo的上值(2)
lua_pushcclosure(L,echo,2); //2代表函数echo的上值个数
lua_setfield(L,-2,"echo"); //该函数用于将栈顶的值赋给指定表中的字段。如果表不存在,则会自动创建。
return 1;
}
test.lua
-- 加载c动态库 找到uv.so
package.cpath = package.cpath .. ";./?.so;"
local uv=require "uv" -- 从c代码中得到一个k,v表
print("hello world")
三、c代码申请一块内存userdata供lua使用
实现功能 能够创建一个log对象,可以记录打印信息的次数并且可以打印10次最近的历史记录
lua文件不过多描述
c文件
首先创建一个tab ={"newlog",newlog}表, tab["newlog"]= newlog(函数指针)
然后把这个表返回到lua层 ,因此lua代码即可调用 tab中函数。
newlog() 函数实现 :调用lua_newuserdata() 相当于malloc 一块内存,将这块内存转化为用户定义的对象类型,初始化该对象的成员变量。
lua_createtable(L,10,0)即创建了一个类似于stirng[10]的循环数组来存放打印记录
luaL_newmetatable()创建一个元表并且设置好元方法,并绑定到userdata。(类似于类中成员函数绑定到这个类中)
因此这块内存中既有了成员变量也有了成员函数。
lua文件
package.cpath = package.cpath .. ";./?.so;"
local ud=require "ud"
local log=ud.new()
log:printLog("yangdonghai")
local log1=ud.new()
log1:printLog("民主")
log1:printLog("富强")
log1:printLog("爱国")
log1:printLog("敬业")
log1:printLog("文明")
log1:printLog("友善")
log1:printLog("法制")
log1:printLog("和谐")
log1:printLog("自由")
log1:printLog("平等")
log1:printLogHistory()
c文件
#include<stdio.h>
#include<stdlib.h>
#include<lua.h>
#include<lualib.h>
#include<lauxlib.h>
struct log{
int cnt;
};
static int printLog(lua_State*L){
struct log*ptr=(struct log*)luaL_checkudata(L,1,"aron.log.newLog");
ptr->cnt++;
const char*str=lua_tostring(L,-1);
printf("print[%s]cnt[%3d] \n",str,ptr->cnt);
lua_getuservalue(L,1);//从userdata获取到用于存放记录的表 1为userdata索引
lua_pushvalue(L,2);//把索引为二的值(str)复制到栈顶
lua_seti(L,3,(ptr->cnt-1)%10+1);//把栈顶元素设置到索引为3的数组当中
return 0;
}
static int printLogHistory(lua_State*L){
struct log*ptr=(struct log*)luaL_checkudata(L,1,"aron.log.newLog");
lua_getuservalue(L,1);
if(ptr->cnt<=10){
for(int i=ptr->cnt;i>=1;i--){
lua_geti(L,-1,i);// -1 代表虚拟栈中 userdata关联的数组
printf("cnt=%3d : %s\n",i,lua_tostring(L,-1));
lua_pop(L,1);
}
}else{
for(int i=0;i<10;i++){
int cnt=ptr->cnt-i;
int idx=(cnt-1)%10+1;
lua_geti(L,-1,idx);//从userdata关联的数组中弹出str到虚拟栈中
printf("cnt=%3d : %s\n",cnt,lua_tostring(L,-1));
lua_pop(L,1);
}
}
return 0;
}
static int newLog(lua_State*L){
struct log*ptr=(struct log*)lua_newuserdata(L,sizeof(struct log));
ptr->cnt=0;
lua_createtable(L,10,0);//创建一个数组用于保存历史记录
lua_setuservalue(L,-2);//这个tab绑定到userdata中
if(luaL_newmetatable(L,"aron.log.newLog")){
luaL_Reg tab[]={
{"printLog",printLog},
{"printLogHistory",printLogHistory},
{NULL,NULL},
};
luaL_newlib(L,tab);// tab [printLog]=printLog
lua_setfield(L,-2,"__index");
//lua_setmetatable(L,-2);
}
lua_setmetatable(L,-2);
return 1;
}
static const luaL_Reg l[]={
{"new",newLog},
{NULL,NULL},
};
int luaopen_ud(lua_State*L){
luaL_newlib(L,l);//返回一张表出去
return 1;
}