C/C++调用lua实现原理

一、运用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/C++调用lua实现原理_第1张图片

三、堆栈的操作

现在有很多的高级程序员,习惯性地运用封装代码的形式来将C++调用lua给封装在类的内部,但是万变不离其宗,最终都是

在底层还是通过操作堆栈实现的,操作堆栈简单的说就是出栈和入栈。lua堆栈支持多种数据格式压栈,例如数字(包括int、float和

double)、字符串、表、实例对象等等,实例对象我们也可以称作闭包或者黑包,当然也能将函数压入堆栈进行调用。

 1、入栈操作示例:

C/C++调用lua实现原理_第2张图片

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,里面有:

C/C++调用lua实现原理_第3张图片

1、加载lua模块

C/C++调用lua实现原理_第4张图片

2、读取变量

C/C++调用lua实现原理_第5张图片

3、运行函数

C/C++调用lua实现原理_第6张图片

从第3点还可以看出,c++调用lua程序的函数时。对堆栈的操作顺序:

函数入栈、参数入栈,然后lua_pcall调用函数,那么在lua端的堆栈顺序是:参数出栈、保存参数、函数出栈、

调用函数,将返回结果压入堆栈,供C++程序读取结果。

总的来说,C++调用lua遵循一条黄金法则,即C++中产生什么值,lua不关心也不用知道,同样的C++需要什么值什么操作

只要通知lua即可,这些值和操作由lua完成生成,并压入堆栈,而C++只能通过api接口来获取这个值。







你可能感兴趣的:(学习)