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调用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); double b = lua_tonumber(L, -2); lua_pushnumber(L, a + b); lua_pushnumber(L, a * b); 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, "age");// len2 lua_pushstring(L, "120");// len3 lua_rawset(L, -3);// len1 return 1; // 此时堆栈里面就剩下newtable了 } 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"); { // 读取全局变量,并将其放入栈顶 lua_getglobal(L, "str"); // 从栈顶取出字符串数据 cout << "str=" << luaL_checkstring(L,-1) << endl; lua_getglobal(L, "int"); 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"); // 注意读取的顺序 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"); // len=1 lua_getfield(L, -1, "name");// 此时tbl在栈顶,所以第二个参数是-1, len=2 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);
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); }
堆栈情况如下: