在第一个教程中介绍了于C++中运行Lua脚本的方法,在第二课就来介绍如何实现C++与Lua交互。
这一课的主题是要在C++程序中取得Lua脚本内的变量,我们先给出代码再进一步说明:
C++代码:
#include "include\lua.h"
#include "include\lauxlib.h"
#include "include\lualib.h"
#include "windows.h"
void main(int argc, char* argv[])
{
int var=0;
lua_State *pLua = luaL_newstate(); // Lua5.2后的版本遗弃lua_open(),改用luaL_newstate()
if(!pLua)
{
printf("Failed to open Lua.\n");
return;
}
luaL_openlibs(pLua); // Lua5.1以上使用此函数开启库
if(luaL_dofile(pLua, "luaDemo.lua")!=0) // 运行Lua腳本,若返回0则成功
{
printf("Failed to run lua.\n");
return;
}
lua_settop(pLua, 0); // Lua堆栈栈顶索引重置为0
lua_getglobal(pLua, "var"); // 取得Lua脚本中的var变量。
// 此时C++程序会把var字串推入堆栈,然后Lua把var从堆栈中取出,接着在全局表中查找出对应的值,然后把值推入堆栈。
if(lua_isnumber(pLua, -1)!=0) // 判断堆栈顶的值是否为我们要的数字型态的值,若返回非0则正確
{
var = lua_tonumber(pLua, -1); // 取出堆栈栈顶的值
}
printf("%d\n", var);
lua_close(pLua);
system("pause");
return;
}
Lua脚本:
var=5566
代码延续前一篇的架构,不过载入脚本的方法我们稍作修改如下:
luaL_dofile(pLua, "luaDemo.lua");
在程序第20行,使用这个宏来读取Lua脚本并运行;
前一篇中是使用lua_dostring(L, buf); 将字串内容作为Lua脚本运行。
接下来要说明代码的主要部份,量不多,但重在理解,在這之前我们需要理解清楚C++与Lua是如何沟通的,才能搞清楚代码原理。
为了使Lua能和C++交互,Lua必须维护一个Lua堆栈,以及一个Lua全局表(global table);
Lua全局表是一张键值对(key-value)的表,储存Lua脚本中的所有全局变量,每个lua_State结构体都会拥有一个全局表来维护Lua脚本中的全局变量。
Lua堆栈则是C++与Lua沟通的中间人,因为他们不能理解彼此的语言,因此需要藉由一个管道来互相沟通,
当C++想获取Lua中全局变量的值时,需要接着进行以下步骤:
(1) C++把想获取的变量值之变量名以字符串推入堆栈
(2) Lua将该变量名字符串从堆栈中取出
(3) Lua到全局表中查找与变量名相同的键,以及该键对应的值,并且将值返回Lua
(4) Lua把该值推入堆栈
(5) C++就可以从堆栈顶端取得变量对应的值
除了可以获得变量之值以外,C++想调用Lua脚本中的函数得到返回结果时也是透过堆栈沟通。
通过上方的描述,各位应该稍微理解C++取得Lua变量的方式了,若还有些模糊,我们一起从代码实例理解。
在25行我们首先重置C++与Lua互相沟通所使用到的Lua堆栈之索引,呼叫lua_settop函数将堆栈栈顶索引设置为0,0作为第二个参数传入函數;
接着就可以开始取得变量值了,
26行呼叫lua_getglobal函数,将变量名字符串"var"作为第二个参数传入函数,此时变量名var就会推入堆栈,然后Lua就会取出变量名var,找出对应的值,再将值推回堆栈。
OK~ 至此,任务已经完成一半了,最后就是要让C++取得堆栈的内容。
在C++中可以呼叫lua_tonumber这个宏来取得堆栈中的值,取值的索引则是-1,作为第二个参数传入;
顺带一提,在Lua堆栈中用负数表达索引值是由堆栈顶端往下以-1, -2, -3, -4, ...........依序递减;若用正数表达则是由堆栈底端往上以1, 2, 3, 4, .........依序递增;
在本篇的情境下,由于我们的堆栈中只存有一个变量值,因此欲取得此值时可以-1或1指定索引,
如此一来就可以通过函数返回值取得变量值了。
另外,为了增强取值时的安全性,我们可以添加额外的验证,
在29行使用了lua_isnumber这个函数检查我们要取得的变量值是否为我们想要的型态,若函数返回值不为0则验证通过,可继续从堆栈中取得变量值。
以上就是程序的主要运行过程说明,在运行完整代码的情况下,程序将会输出 5566。
谢谢收看,下集待续。