开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情
lua源码
lua官网下载lua源码,自己学习lua和c++相互调用的例子
以下2个文件不需要参与编译,原因是他们是bin文件的源代码,都有Main入口
lua.c
luac.c
加载lua文件
lua_State* L = luaL_newstate();
luaL_loadfile(L, "main.lua");
lua_pcall(L,0,0,0);
// luaL_dofile(L, "main.lua");
lua_close(L);
- dofile和loadfile的区别:
#define luaL_dofile (L, fn) (luaL_loadfile (L, fn ) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_loadfile(L, f ) luaL_loadfilex(L, f,NULL)
lua栈
- 特点:先进后出
- 正数索引1永远表示栈底,负数索引-1永远表示栈顶**
lua_gettop(L); // 获取当前lua栈的大小
lua_pop(L, -1);// 弹出栈顶元素,-1弹出所有,>1弹出指定数量的元素
CPP栈操作
void test1(){
lua_State* L = luaL_newstate();
lua_pushstring(L, "i am string");
lua_pushnumber(L, 100);
if (lua_isstring(L, 1))
{
cout << lua_tostring(L, 1) << endl;
}
if (lua_isnumber(L, 2))
{
cout << lua_tonumber(L, 2) << endl;
}
lua_close(L);
}
堆栈情况如下:
lua调用c++函数(注册全局函数)
注册函数类型:
typedef int (*lua_CFunction) (lua_State *L);
没有返回值的
- lua
print("cpp call me");
- cpp
int print(lua_State* L){
if (lua_isstring(L, -1))
{
cout << lua_tostring(L, -1) << endl;
}
return 0;
}
void main(){
lua_State* L = luaL_newstate();
lua_register(L, "print", print);
luaL_dofile(L, "test.lua");
lua_close(L);
}
返回int,string基础类型
- lua
local sum, mul = add(100, 20);
print("sum: " .. sum);
print("mul:" .. mul)
- cpp
int add(lua_State* L){
// 参数是按照顺序依次压入栈里面
double a = lua_tonumber(L, -1); // 20
double b = lua_tonumber(L, -2); // 100
lua_pushnumber(L, a + b); // sum
lua_pushnumber(L, a * b); // mul
return 2;// 返回的参数个数
}
void main(){
lua_State* L = luaL_newstate();
lua_register(L, "add", add);
luaL_dofile(L, "test.lua");
lua_close(L);
}
返回table类型
- lua
local t = returnTable();
for i, v in pairs(t) do
print("key:" .. i .. ",value:" .. v)
end
- cpp
void returnTable(){
lua_newtable(L);// len1
lua_pushstring(L, "100cm"); //len+1
lua_pushstring(L, "200cm"); //len+1,只会使用这个值
lua_setfield(L, -3, "height");// len-1, -3表示table在栈中的位置
lua_pop(L,1); // 把100cm pop出去
lua_pushstring(L, "age");// len2
lua_pushstring(L, "120");// len3
lua_rawset(L, -3);// 设置到栈顶的表中,并将其从栈上弹出。此时len1
return 1; // 此时堆栈里面就剩下newtable了
// 1表示该C函数将返回给Lua代码的返回值数量
}
void main(){
lua_State* L = luaL_newstate();
luaopen_base(L); // 注册了一些内置的基础函数:ipairs、pairs、print
lua_register(L, "returnTable", returnTable);
luaL_dofile(L, "test.lua");
lua_close(L);
}
遇到的一个报错
attempt to call a nil value (global 'pairs')
很明显,提示找不到pairs=nil,难道pairs不是lua的关键字?
是的,这是lua的内置基础函数
cpp调用lua的变量
一般我们不需要调用lua的函数,大部分情况都是lua调用c++的实现
- lua
str="string"
int=100
- cpp
lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaVar.lua");
// get后,立刻读取,所以使用-1没问题
{
// 读取全局变量,并将其放入栈顶
lua_getglobal(L, "str");// stack len = 1
// 从栈顶取出字符串数据
cout << "str=" << luaL_checkstring(L,-1) << endl;
lua_getglobal(L, "int"); // stack len = 2
cout << "int=" << luaL_checkinteger(L, -1) << endl;
cout << "len=" << lua_gettop(L) << endl; // 此时栈的大小为2
}
lua_close(L);
lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaVar.lua");
{
lua_getglobal(L, "str");
lua_getglobal(L, "int");
// 和上边的代码不同的是,读取堆栈的方式不同,先get,后读取,所以必须使用1、2
cout << "str=" << luaL_checkstring(L, 1) << endl;
cout << "int=" << luaL_checkinteger(L, 2) << endl;
cout << "len=" << lua_gettop(L) << endl; // 此时栈的大小为2
}
lua_close(L);
从以上2个例子中可以看出,lua_getglobal会依次将查找到的值放入栈顶,使用的时候需要栈的顺序
关于luaL_check*的api:
LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) {
int isnum;
lua_Integer d = lua_tointegerx(L, arg, &isnum);
if (l_unlikely(!isnum)) {
interror(L, arg);
}
return d;
}
static void interror (lua_State *L, int arg) {
if (lua_isnumber(L, arg))
luaL_argerror(L, arg, "number has no integer representation");
else
tag_error(L, arg, LUA_TNUMBER);
}
lua_is*这类的函数可以判断栈中的数据类型,但是需要注意int->string的隐形转换。
cpp调用lua的table
- lua
tbl = {
name = "lua",
100,
{
id = 10,
}
}
- cpp通过key获取值
lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaTable.lua");
lua_getglobal(L, "tbl"); // stack len = 1
// 获取指定表中指定字段的值并将其推入 Lua 栈顶
lua_getfield(L, -1, "name");// stack len = 2, 此时tbl在栈顶,所以第二个参数是-1
cout << "tbl.name=" << luaL_checkstring(L, -1) << endl;
lua_close(L);
lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaTable.lua");
lua_getglobal(L, "tbl"); // len=1
lua_pushstring(L, "11");// 这个是干扰项,len=2
lua_pushstring(L, "name");// len=3
// 从栈顶取出一个元素(name)并且返回把查找到的值压入栈顶
lua_gettable(L, 1); // len=3
cout << lua_tostring(L, -1);
lua_close(L);
- cpp获取无序的值
lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaTable.lua");
lua_getglobal(L, "tbl"); // len=1
// -1表示tbl在栈顶, 1表示取tbl[1]
lua_rawgeti(L, -1, 1);// len=2
// 将tbl[1]的值放在了栈顶,因为tbl[1]=100
cout << "tbl[1]=" << lua_tointeger(L, -1) << endl;
lua_pop(L,1); // 弹出tbl[1]的值,len=1
// 获取嵌套的table
lua_rawgeti(L,-1,2);// 此时栈顶是tbl,直接获取tbl[2]元素,len=2
lua_getfield(L,-1,"id");//将id的值放在栈顶,len=3
cout << lua_tointeger(L, -1);
lua_close(L);
cpp调用lua的函数
- lua
function add(a, b)
return a + b;
end
- cpp
lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaFunction.lua");
lua_getglobal(L, "add");// len=1
lua_pushnumber(L, 10);// len=2
lua_pushnumber(L, 20);// len=3
// 2表示参数数量,1表示返回值个数,0表示错误处理函数在栈中的索引值,压入结果前会弹出函数和参数
// 弹出函数地址和所有参数,并将返回值压入栈顶
int ret = lua_pcall(L, 2, 1, 0); // len=1
cout << "add result is: " << luaL_checkinteger(L, -1) << endl;
lua_close(L);