一.配置Lua C++交互环境
1.下载Lua 包环境
地址: https://www.lua.org/download.html ,我们这里用的是5.4.2版本。
2.新建C++ 控制台应用程序
3.导入Lua 源码
1)导入Lua 源码到同级目录(这样做为了Main函数所在类添加Lua 的C 类的时候直接可以include,不需要考虑目录层级问题)
打开的目录里,将5.4.2 的lua包里的 src目录里的文件全部拷到此目录
2)添加Lua 源码
选中刚刚导入的Lua文件
3)编译
这时,点击目录生成,回发现报错
这是关键报错信息,重复main头文件,众所周知,main函数是启动函数;那就注释调main.
会发现,有两处main ,lua.c 中 int main 和luac.c int main,分别都注释了。(或者简单粗暴,直接将luc.c和luac.c直接删除也可以)
再点生成,成功。这两处main,其实就是如果你将此lua编码打包成exe,就是启动函数。但是我们这里不需要这边的main,我们自己新建的C++ 应用程序,是有自己的Main。
二.Hello.lua 运行
新建Lua脚本,必须.lua 结尾。
1.关键API
1)lua与C++交互,必须要一个虚拟栈。可通过lua_State* L = luaL_newstate(); 对于栈的介绍可参考:https://blog.csdn.net/shun_fzll/article/details/39120965,这里就不对栈作描述了。
2)加载Lua文件,可通过 luaL_dofile 返回一个 int类型,返回结果不为0,则表示异常
3)Lua有异常,会把返回结果返回到栈顶,也就是说报异常了,可以通过lua_tostring(L,-1)得到报啥错,再打印出来.
4)lua_close 就是释放这个栈。
5)对于C++调用 C的头文件,需要extern
2.实例分析
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 extern "C" 5 { 6 #include "lua.h" 7 #include "lualib.h" 8 #include "lauxlib.h" 9 } 10 int main() 11 { 12 std::cout << "Hello World!\n"; 13 lua_State* L = luaL_newstate(); 14 int Ret = luaL_dofile(L, "LuaHello.lua"); 15 if (Ret) 16 { 17 string strError = lua_tostring(L, -1); 18 cout << strError.c_str() << endl; 19 return -1; 20 } 21 22 lua_close(L); 23 return 0; 24 }
1)运行上述代码
2)想一下,好像lua代码是运行了,但是print怎么会nil,并报错,提示的还挺智能,具体行号都报出来了。
我们再试着修改Lua代码中下移两行试试:
3)咦,那就证明Lua文件是肯定运行了,就是异常了。找不到print,print不是lua库里的函数嘛,为啥拿不到了。
因为C++环境中创建Lua_State这个栈,这个默认并没有打开lua标准库。所以查一下。
在 上述Line:13 后面新增 luaL_openlibs(L);
运行 得到
恭喜,C++ 与Lua通信成功。
三.Lua UserData应用实例
关于具体lua与C交互的一些常见操作,可参考:https://blog.csdn.net/shun_fzll/article/details/39120965
问题:有时候,你会想,我在C++中声明了一个struct,在lua中,也想声明这个struct,怎么弄纳?接下来这个案例就是教你如何使。
我们的UserData就是解决这个问题的。
Lua UserData分两种,我们这说的是FullUserData,就是可以解决上述问题的UserData.
直奔主题,看代码分析。
Lua5.1之前和之后的注册函数差距很大,详情可参考:https://blog.csdn.net/ljhjason/article/details/28860633
Lua5.1之后可以使用 luaL_requiref 代替 Lua5.1之前的luaL_register ,可参考:https://blog.csdn.net/ljhjason/article/details/28860633
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 extern "C" 5 { 6 #include "lua.h" 7 #include "lualib.h" 8 #include "lauxlib.h" 9 } 10 11 struct TestCStruct 12 { 13 char* Name; 14 int Num = 1; 15 }; 16 17 int NewTestCStruct(lua_State* L) 18 { 19 size_t iBytes = sizeof(struct TestCStruct); 20 struct TestCStruct* pStruct = (struct TestCStruct*)lua_newuserdata(L, iBytes); 21 return 1; 22 } 23 24 int SetNum(lua_State* L) 25 { 26 struct TestCStruct *pStruct = (struct TestCStruct*)lua_touserdata(L, 1); 27 luaL_argcheck(L, pStruct != NULL, 1, "Error Param"); 28 int num = luaL_checkinteger(L, 2); 29 luaL_argcheck(L, num > 0, 2,"Wrong Paramter"); 30 pStruct->Num = num; 31 return 1; 32 } 33 34 int GetNum(lua_State* L) 35 { 36 struct TestCStruct *pStruct = (struct TestCStruct*)lua_touserdata(L, 1); 37 luaL_argcheck(L, pStruct != NULL, 1, "ErrorStruct"); 38 lua_pushinteger(L, pStruct->Num); 39 return 1; 40 } 41 42 struct luaL_Reg arrayFunc[] = { 43 {"new",NewTestCStruct}, 44 {"SetNum",SetNum}, 45 {"SNum",GetNum}, 46 {NULL,NULL} 47 }; 48 49 LUALIB_API int luaopen_mytest(lua_State* L) 50 { 51 luaL_newlib(L, arrayFunc); 52 return 1; 53 } 54 55 int main() 56 { 57 std::cout << "Hello World!\n"; 58 lua_State* L = luaL_newstate(); 59 luaL_openlibs(L); 60 luaL_requiref(L, "mytest", luaopen_mytest, 0); 61 int Ret = luaL_dofile(L, "LuaHello.lua"); 62 if (Ret) 63 { 64 string strError = lua_tostring(L, -1); 65 cout << strError.c_str() << endl; 66 return -1; 67 } 68 69 lua_close(L); 70 return 0; 71 }
Lua中源码
local t = require("mytest") print("t:" .. tostring(t)) local y = t.new() print("y :" .. tostring(y)) t.SetNum(y,100) print("Num:" ..t.SNum(y)) local y2 = t.new() print("y2 :" .. tostring(y2)) print("Hello lua and C++")
运行结果
综上, 可以看到Full UserData 的使用,主要核心是Line:60 luaL_requiref的使用。
请发表评论