本文共 6709 字,大约阅读时间需要 22 分钟。
理论
Lua是一门动态脚本语言,运行依托于宿主语言,可以是C、C++、C#、golang等,只要实现了Lua解释器就可以。所以,Lua从设计来讲就是动态脚本语言,正是因为它是解释性语言,所以它更充当了这些宿主语言的“缝合”作用,是为“胶水”性语言
lua中的栈
lua中的栈是一个很奇特的数据结构,普通的栈只有一排索引,但是在lua中有两排索引,正数1索引的位置在栈底,负数-1索引的位置在栈顶。如下图所示。
根据结构图,我们不需要知道栈的大小,我们就可以确定的栈顶和栈底的位置
- 当索引是1的时候对应的是栈底
- 当索引是-1的时候对于的是栈顶。
常用的lua api
lua_State* L=luaL_newstate();
luaL_newstate()函数返回一个指向堆栈的指针- lua_createtable(L,0,0);新建并压入一张表
- lua_pushstring(L,0,0);压入一个字符串
- lua_pushnumber(L,0,0);压入一个数字
- lua_tostring(L,1);取出一个字符串
- lua_tointeger(L,1);取出数字
- double b=lua_tonumber();取出一个double类型的数字
- lua_load()函数 当这个函数返回0时表示加载
- luaL_loadfile(filename) 这个函数也是只允许加载lua程序文件,不执行lua文件。它是在内部去用lua_load()去加载指定名为filename的lua程序文件。当返回0表示没有错误。
- luaL_dofile 这个函数不仅仅加载了lua程序文件,还执行lua文件。返回0表示没有错误。
- lua_push*(L,data)压栈
- lua_to*(L,index)取值
- lua_pop(L,count)出栈
- lua_close(L);释放lua资源
- lua_getglobal(L, “val”);//获取全局变量的val的值,并将其放入栈顶
Lua中调用CPP函数
Lua可以调用C函数的能力极大的提高了Lua的可扩展性和可用性。对有些和操作系统相关的功能,或者是对效率要求较高的模块,我们完全可以通过C函数来实现,之后再通过Lua调用指定的C函数。
对于那些可被Lua调用的C函数而言,其接口必须遵循Lua要求的形式,即typedef int (*lua_CFunction)(lua_State* L)
.。解析一下该形式:
- 该函数类型仅仅包含一个表示Lua环境的指针作为其唯一的参数,实现者可以通过该指针进一步获取Lua代码中实际传入的参数。
- 返回值是整型,表示该C函数将返回给Lua代码的返回值数量,如果没有返回值,则return 0即可
- 需要说明的是,C函数无法直接将真正的返回值返回给Lua代码,而是通过虚拟栈来传递Lua代码和C函数之间的调用参数和返回值的
可能出现的错误
a.cpp:8: 警告:不建议使用从字符串常量到‘char*’的转换/tmp/ccij5HeF.o:在函数‘main’中:a.cpp:(.text+0xe):对‘luaL_newstate()’未定义的引用a.cpp:(.text+0x24):对‘luaL_openlibs(lua_State*)’未定义的引用a.cpp:(.text+0x60):对‘luaL_loadbufferx(lua_State*, char const*, unsigned int, char const*, char const*)’未定义的引用a.cpp:(.text+0x9b):对‘lua_pcallk(lua_State*, int, int, int, int, int (*)(lua_State*, int, int))’未定义的引用a.cpp:(.text+0xe4):对‘lua_tolstring(lua_State*, int, unsigned int*)’未定义的引用a.cpp:(.text+0x107):对‘lua_settop(lua_State*, int)’未定义的引用a.cpp:(.text+0x140):对‘lua_close(lua_State*)’未定义的引用
解决方法:
原来是因为lua是C语言模块,用g++调用c语言的库需要在包含头文件时加上extern “C”,就能正常编译了,即修改为
extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h"}
原因:
因为Lua是用C语言写的,除非编译lua库时指定编译器强制以C++方式编译,否则在C++工程中应该这样包含lua头文件:
extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h"}
准备
安装lua编译器(没有动态链接库)
在Linux系统安装Lua,使用下面的命令下载并生成Lua程序:
$ wget http://www.lua.org/ftp/lua-5.2.3.tar.gz$ tar zxf lua-5.2.3.tar.gz$ cd lua-5.2.3$ make linux test
在其它系统上安装Lua时,比如aix,ansi,bsd,generic,linux,mingw,posix,solaris,你需要将make linux test命令中的linux替换为相应的系统平台名称。
指向完成之后可以在src目录下生成liblua.a
错误
lua.c:67:31: 致命错误:readline/readline.h:没有那个文件或目录 #include^编译中断。make[2]: *** [lua.o] 错误 1make[2]: 离开目录“/home/oceanstar/workspace/cpp/lua-5.2.3/src”make[1]: *** [linux] 错误 2make[1]: 离开目录“/home/oceanstar/workspace/cpp/lua-5.2.3/src”make: *** [linux] 错误 2
解决:
yum install libtermcap-devel ncurses-devel libevent-devel readline-devel
注意
在linux下编译安装lua默认是不会生成liblua.so文件的,如果想要生成liblua.so文件需要修改makefile文件。 要么自己直接到去下载。生成方法可以参考
环境搭建好后,所有C/C++代码需要引用lua.hpp或lua.h, lualib.h, lauxlib.h,运行需要连接liblua.so
C/C++调用Lua
文件目录结构
lua测试代码
test.lua
name = "bob"age= 20mystr="hello lua"mytable={ name="tom",id=123456}function add(x,y) return 2*x+yend
示例1:通过C语言读取Lua中的变量
main.cpp
#includeextern "C" { #include "lua.h"#include "lauxlib.h"#include "lualib.h"};int main(){ lua_State *L = luaL_newstate(); luaL_openlibs(L); int retLoad = luaL_loadfile(L, "/home/oceanstar/CLionProjects/untitled1/src/test.lua"); if (retLoad == 0) { printf("load file success retLoad:%d\n", retLoad); } if (retLoad || lua_pcall(L, 0, 0, 0)) { printf("error %s\n", lua_tostring(L, -1)); return -1; } lua_getglobal(L, "name"); //lua获取全局变量name的值并且返回到栈顶 lua_getglobal(L, "age"); //lua获取全局变量age的值并且返回到栈顶,这个时候length对应的值将代替width的值成为新栈顶 //注意读取顺序 int age = lua_tointeger(L, -1); //栈顶 const char *name = lua_tostring(L, -2);//次栈顶 printf("name = %s\n", name); printf("age = %d\n", age); lua_close(L); return 0;}
测试结果:
这里面需要注意的是,当出现多个lua_getglobal()函数的时候由上到下,依次压入栈,在使用lua_to*(L,index)函数读取栈顶元素的时候,如果每次压入栈的数据类型都不一样,那么在读取的是就要注意读取顺序。当使用lua_tointegers()的是,返回值类型的long long
#define LUA_INTEGER long longtypedef LUA_INTEGER lua_Integer;LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
当使用lua_tolstring()的时候,返回值类型是const char*
LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
当使用lua_tonumber()的是,返回值类型是double
#define LUA_NUMBER doubletypedef LUA_NUMBER lua_Number;LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
示例2:通过C语言调用Lua中的函数
main.cpp
#includeextern "C" { #include "lua.h"#include "lauxlib.h"#include "lualib.h"};int main(){ lua_State *L = luaL_newstate(); luaL_openlibs(L); int retLoad = luaL_loadfile(L, "/home/oceanstar/CLionProjects/untitled1/src/test.lua"); if (retLoad || lua_pcall(L, 0, 0, 0)) { printf("error %s\n", lua_tostring(L, -1)); return -1; } //调用函数,依次压入参数 lua_getglobal(L, "add"); lua_pushnumber(L, 10); lua_pushnumber(L, 20); //查看压入栈的元素 for (int i=1;i<3;i++) { printf("number:%f\n",lua_tonumber(L, -i)); } //lua_pcall(L,2,1,0):传入两个参数 期望得到一个返回值,0表示错误处理函数在栈中的索引值,压入结果前会弹出函数和参数 int pcallRet = lua_pcall(L, 2, 1, 0); //lua_pcall将计算好的值压入栈顶,并返回状态值 if (pcallRet != 0) { printf("error %s\n", lua_tostring(L, -1)); return -1; } int val = lua_tonumber(L, -1); //在栈顶取出数据 printf("val:%d\n", val); lua_pop(L, -1); //弹出栈顶 //再次查看栈内元素,发现什么都没有,因为lua在返回函数计算值后会清空栈,只保留返回值 for (int i=1;i<3;i++) { printf("number:%f\n",lua_tonumber(L, -i)); } lua_close(L); return 0;}
结果:
由结果可以看出来,当调用完lua中的函数以后,会自动清空栈,只保留结果在栈顶。注意:这个时候我们修改一下test.lua中的add函数:把2改为4
function add(x,y) return 4*x+yend
这时不进行编译,直接再运行一下./main,可以看到这个结果改变了从40变成了60,这是在我们没有进行重复编译的情况下直接产生的变化。
这就可以看出lua在C/C++语言中的嵌入特性,Lua中的函数就像是文本一样被读取,但是又确实是作为程序被执行。当我们的项目很大时,每次编译都需要十几分钟,这个时候如果合理的利用lua特性,仅仅是修改lua文件就可以避免这十几分钟的空白时间。
实例3:通过C语言调用Lua中的table
#includeextern "C" { #include "lua.h"#include "lauxlib.h"#include "lualib.h"};int main(){ lua_State *L = luaL_newstate(); luaL_openlibs(L); int retLoad = luaL_loadfile(L, "/home/oceanstar/CLionProjects/untitled1/src/test.lua"); if (retLoad || lua_pcall(L, 0, 0, 0)) { printf("error %s\n", lua_tostring(L, -1)); return -1; } printf("读取lua table中对应的值\n"); //将全局变量mytable压入栈 lua_getglobal(L, "mytable"); //压入表中的key lua_pushstring(L, "name"); //lua_gettable会在栈顶取出一个元素并且返回把查找到的值压入栈顶 lua_gettable(L, 1); const char *name = lua_tostring(L, -1); //在栈顶取出数据 printf("name:%s\n", name); lua_pushstring(L,"id");//压入id lua_gettable(L, 1);//在lua mytable表中取值返回到栈顶 int id = lua_tonumber(L, -1); //在栈顶取出数据 printf("id:%d\n", id); lua_close(L); return 0;}
Lua调用C/C++
文章目录
转载地址:https://blog.csdn.net/zhizhengguan/article/details/122462700 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!