一、运用lua脚本与C++结合的优势
lua作为一种脚本语言,在与C++程序配合使用时,有着很大的优势,尤其在为C++程序做参数解析时,更新通信数据格式时,无需更改C++代码进行重新编译,只需要更改lua脚本程序即可。
lua与C/C++的数据通信是基于共享内存,即lua堆栈实现的,这使得lua程序在与C++程序混合使用时,还存在一个对于C/C++程序的一个天然优势,就是在lua内部不需要进行实例的delete操作:
1、lua中,number(C++中的int)、boolean、nil、light userdata四种类型的值是直接存储在lua堆栈上元素里的,和垃圾回收无关;
2、lua中,table、string、thread、userdata和closure等类型是以指针的形式存放在堆栈里的,它们在生命周期结束时,会被自动地垃圾回收。
二、什么是lua堆栈
lua堆栈是一个虚拟堆栈,遵循先进后出的原则,但其本质上就是一个struct结构体。堆栈的索引可以是正数,也可以是负数,区别在于
正数1索引的位置在栈底,负数-1索引的位置在栈顶。如下图所示。
三、堆栈的操作
现在有很多的高级程序员,习惯性地运用封装代码的形式来将C++调用lua给封装在类的内部,但是万变不离其宗,最终都是
在底层还是通过操作堆栈实现的,操作堆栈简单的说就是出栈和入栈。lua堆栈支持多种数据格式压栈,例如数字(包括int、float和
double)、字符串、表、实例对象等等,实例对象我们也可以称作闭包或者黑包,当然也能将函数压入堆栈进行调用。
1、入栈操作示例:
2、出栈操作示例:
当然对于lua堆栈还有一些别的操作,不仅仅是出栈和入栈,但本文由于篇幅和主题,目前只举例此两种,上述代码中的
luaL_newstate()可以将其视作: luaL_newstate()函数返回一个指向堆栈的指针。此处还涉及到lua的3个头文件:
lua.h,luaxlib.h和lualib.h。需要注意的是堆栈操作是基于栈顶的。
四、C++加载lua模块
其实C++调用lua脚本,我们可以很形象的认为lua程序是一个模块,而往往我们在调用的时候是以文件的形式展开的
,所以往往调用之前务必要加载lua程序文件。lua提供了接口工外部加载自身。
1、lua_load函数
这个函数的原型是 int lua_load(lua_State* L,lua_Reader reader,void* data,const char* chunckname),当这个函数返回0时表示加载
成功,否则加载失败,当然这个函数只允许加载lua程序文件,不能运行lua程序文件的。
2、luaL_loadfile
这个函数也是只允许加载lua程序文件,不可执行的。它是在内部去用lua_load去加载指定名为filename的lua程序文件,如果
输入文件filename为空,则从标准输入中加载,如果加载的lua程序文件的第一行存在#字样,则忽略第一行。返回0表示没有错误。
3、luaL_dofile
这个函数的定义是:(luaL_loadfile(L,filename) || lua_pcall(L,0,LUA_MULTRET,0)),显然这个函数不仅仅加载了lua程序文件,还
执行了它。返回0表示没有错误。
五、应用举例。
例如有个lua的程序文件叫test.lua,里面有:
1、加载lua模块
2、读取变量
3、运行函数
从第3点还可以看出,c++调用lua程序的函数时。对堆栈的操作顺序:
函数入栈、参数入栈,然后lua_pcall调用函数,那么在lua端的堆栈顺序是:参数出栈、保存参数、函数出栈、
调用函数,将返回结果压入堆栈,供C++程序读取结果。
总的来说,C++调用lua遵循一条黄金法则,即C++中产生什么值,lua不关心也不用知道,同样的C++需要什么值什么操作
只要通知lua即可,这些值和操作由lua完成生成,并压入堆栈,而C++只能通过api接口来获取这个值。