http://chenlq.net/dev/cpp-why/50-half-performance-half-of-the-flexible-c-and-lua-hybrid-programming-how-lua-script-function-call-in-the-c-code.html
[50]一半是性能,一半是灵活——C++和Lua混合编程(如何在C++代码中调用Lua脚本的函数?)
Q:
在[49]一半是性能,一半是灵活——C++和Lua混合编程(如何在C++中执行Lua脚本?)中,我们介绍了如何在C++程序化中执行Lua脚本,然而很多时候,我们并不需要执行整个脚本,而是只要执行脚本中的某个函数完成某个功能就可以了,那么,如何在C++代码中执行Lua脚本中的函数呢?
A:
在C++代码中执行Lua脚本的函数,跟直接执行Lua脚本非常相似,只是因为函数的执行涉及到函数名的查找,参数以及返回值的传递,所以多了一些将参数和返回值出栈入栈的操作,而这些,Lua都提供了相应的函数(lua_getglobal()获取函数,lua_pushnumber()参数入栈,lua_call()调用函数)来完成,使用起来也非常方便。
我们来看一个具体的例子,在贪吃蛇游戏中,我们需要判断当前贪吃蛇到达的位置是否还在场景之内(isinscene()函数)。如果我们把这个判断逻辑以如下的形式固化在程序当中:
bool isinscene(int x,int y)
{
if(x > 0 && x < 100
&& y > 0 && y < 100 )
{
return true;
}
else
{
return false;
}
}
那么,整个程序就失去了灵活性,这个程序只能将场景限制在(0,0,100,100)范围之内,如果我们的需求发生了变化,场景变大或者是变小,我们不得不修改源代码,然后重新编译并发布给客户。
而如果是使用在C++代码中调用Lua函数来实现这种容易变化的逻辑,那么,整个程序将灵活得多。
要做到这一点,首先在C++代码中搭建起调用Lua函数的框架:
// 引入Lua需要的头文件
// 如果是C语言代码,extern "C"可以省略
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
};
#include <iostream>
// 判断x,y是否在场均内
bool inscene(lua_State* L,int x,int y)
{
bool isin = false; // 初始值,未在场景内
if(nullptr != L)
{
// 根据函数名获得Lua中的函数
lua_getglobal(L, "inscene");
lua_pushnumber(L, x); // 参数一入栈
lua_pushnumber(L, y); // 参数二入栈
// 调用Lua中的inscene函数,
// 这里的2,1表示两个输入参数,一个返回值
lua_call(L, 2, 1);
// 获得bool类型的返回值
isin = lua_toboolean(L, -1);
lua_pop(L, 1);// 将返回值出栈,恢复栈中的元素
}
return isin;
}
// C++程序执行Lua脚本
int main()
{
// Lua解释器指针
lua_State* L = nullptr;
// 创建Lua解释器
L = luaL_newstate();
if(nullptr != L)
{
luaL_openlibs(L);// 打开Lua库
// 执行Lua脚本snake.lua
luaL_dofile(L, "snake.lua");
int x = 10;
int y = 40;
// 调用Lua脚本中的函数
bool isin = inscene(L, x, y);
// 输出结果
if(isin)
std::cout<<x<<","<<y<<" is in the scene."<<std::endl;
lua_close(L);// 关闭Lua
}
return 0;
}
这样,C++程序通过调用Lua脚本中的inscene函数来完成逻辑判断,相当于将游戏逻辑下放到了Lua脚本中,而Lua脚本的修改是相对比较容易的,只需要简单修改就可以直接使用(无需重新编译),可以很好地满足C++程序对于灵活性的要求。
这里,我们的snake.lua脚本是:
--判断点(x,y)是否在场景内
function inscene(x,y)
local boolean isin = false;
if x > 0 and x < 100
and y > 0 and y < 100 then
isin = true
end
return isin;
end
这样,我们就可以直接在Lua脚本中修改游戏逻辑,而无需对C++程序进行修改和重新编译。
最后还要提到的一点是,虽然C++程序和动态链接库结合的方式,一定程度上也可以让程序更加灵活(每个动态链库可以单独更新以适应新的需求),然而动态链接库的更新,仍然需要修改代码并重新编译,总体而言,仍旧没有Lua脚本灵活。所以,C++程序加上Lua脚本,比较适合于那些对性能要求不是太高,而对灵活性有更多要求的场景(比如游戏),而C++程序加上动态链接库的方式,更适合于那些对性能要求较高,而对灵活性要求不高的场景(比如大型软件)。总之,两种方式各有所长,将他们应用在各自最擅长的场景下,就最好了。
我们能在C++程序中执行Lua脚本或者调用Lua中的函数来增加C++程序的灵活性,反过来,那么我们是不是也可以在Lua脚本程序中调用C++的函数,来提高Lua脚本程序的性能呢?
[50]一半是性能,一半是灵活——C++和Lua混合编程(如何在C++代码中调用Lua脚本的函数?)
Q:
在[49]一半是性能,一半是灵活——C++和Lua混合编程(如何在C++中执行Lua脚本?)中,我们介绍了如何在C++程序化中执行Lua脚本,然而很多时候,我们并不需要执行整个脚本,而是只要执行脚本中的某个函数完成某个功能就可以了,那么,如何在C++代码中执行Lua脚本中的函数呢?
A:
在C++代码中执行Lua脚本的函数,跟直接执行Lua脚本非常相似,只是因为函数的执行涉及到函数名的查找,参数以及返回值的传递,所以多了一些将参数和返回值出栈入栈的操作,而这些,Lua都提供了相应的函数(lua_getglobal()获取函数,lua_pushnumber()参数入栈,lua_call()调用函数)来完成,使用起来也非常方便。
我们来看一个具体的例子,在贪吃蛇游戏中,我们需要判断当前贪吃蛇到达的位置是否还在场景之内(isinscene()函数)。如果我们把这个判断逻辑以如下的形式固化在程序当中:
bool isinscene(int x,int y)
{
if(x > 0 && x < 100
&& y > 0 && y < 100 )
{
return true;
}
else
{
return false;
}
}
那么,整个程序就失去了灵活性,这个程序只能将场景限制在(0,0,100,100)范围之内,如果我们的需求发生了变化,场景变大或者是变小,我们不得不修改源代码,然后重新编译并发布给客户。
而如果是使用在C++代码中调用Lua函数来实现这种容易变化的逻辑,那么,整个程序将灵活得多。
要做到这一点,首先在C++代码中搭建起调用Lua函数的框架:
// 引入Lua需要的头文件
// 如果是C语言代码,extern "C"可以省略
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
};
#include <iostream>
// 判断x,y是否在场均内
bool inscene(lua_State* L,int x,int y)
{
bool isin = false; // 初始值,未在场景内
if(nullptr != L)
{
// 根据函数名获得Lua中的函数
lua_getglobal(L, "inscene");
lua_pushnumber(L, x); // 参数一入栈
lua_pushnumber(L, y); // 参数二入栈
// 调用Lua中的inscene函数,
// 这里的2,1表示两个输入参数,一个返回值
lua_call(L, 2, 1);
// 获得bool类型的返回值
isin = lua_toboolean(L, -1);
lua_pop(L, 1);// 将返回值出栈,恢复栈中的元素
}
return isin;
}
// C++程序执行Lua脚本
int main()
{
// Lua解释器指针
lua_State* L = nullptr;
// 创建Lua解释器
L = luaL_newstate();
if(nullptr != L)
{
luaL_openlibs(L);// 打开Lua库
// 执行Lua脚本snake.lua
luaL_dofile(L, "snake.lua");
int x = 10;
int y = 40;
// 调用Lua脚本中的函数
bool isin = inscene(L, x, y);
// 输出结果
if(isin)
std::cout<<x<<","<<y<<" is in the scene."<<std::endl;
lua_close(L);// 关闭Lua
}
return 0;
}
这样,C++程序通过调用Lua脚本中的inscene函数来完成逻辑判断,相当于将游戏逻辑下放到了Lua脚本中,而Lua脚本的修改是相对比较容易的,只需要简单修改就可以直接使用(无需重新编译),可以很好地满足C++程序对于灵活性的要求。
这里,我们的snake.lua脚本是:
--判断点(x,y)是否在场景内
function inscene(x,y)
local boolean isin = false;
if x > 0 and x < 100
and y > 0 and y < 100 then
isin = true
end
return isin;
end
这样,我们就可以直接在Lua脚本中修改游戏逻辑,而无需对C++程序进行修改和重新编译。
最后还要提到的一点是,虽然C++程序和动态链接库结合的方式,一定程度上也可以让程序更加灵活(每个动态链库可以单独更新以适应新的需求),然而动态链接库的更新,仍然需要修改代码并重新编译,总体而言,仍旧没有Lua脚本灵活。所以,C++程序加上Lua脚本,比较适合于那些对性能要求不是太高,而对灵活性有更多要求的场景(比如游戏),而C++程序加上动态链接库的方式,更适合于那些对性能要求较高,而对灵活性要求不高的场景(比如大型软件)。总之,两种方式各有所长,将他们应用在各自最擅长的场景下,就最好了。
我们能在C++程序中执行Lua脚本或者调用Lua中的函数来增加C++程序的灵活性,反过来,那么我们是不是也可以在Lua脚本程序中调用C++的函数,来提高Lua脚本程序的性能呢?