《C++的十万个为什么》 [50]一半是性能,一半是灵活——C++和Lua混合编程(怎么在C++代码中调用Lua脚本的函数?)

《C++的十万个为什么》 [50]一半是性能,一半是灵活——C++和Lua混合编程(如何在C++代码中调用Lua脚本的函数?)
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);
        // 输出结果