C++ 和lua交互学习的三个例子

C++ 和 Lua 交互学习

Lua简介及安装

Lua的优点:

  • 最快的脚本语言
  • 可以编译调试
  • 与C/C++结合容易
  • Lua是对性能有要求的必备语言

Lua的应用:

  • 游戏的任务脚本,后端服务器
  • AlphaGo: C++ + lua实现
  • 视频服务器、入侵检测脚本、防火墙脚本

Lua的官网: http://www.lua.org/versions.html

  • 5.1 较快
  • 5.3 性能有些下降

Lua的安装

C++ 调用 lua之前需要先安装lua,可以下载lua的源码进行编译安装,在CentOS平台下,还可以直接使用yum安装,CentOS默认使用lua的版本是5.1的版本,如:

yum install lua lua-devel

Lua 的基本概念

Lua的基本数据类型:

  • nil:表示没有数据,当希望释放数据时,直接将nil赋值给该变量即可
  • boolean:在lua中除了false和nil为假,其他都为真,true|false
  • numbers类型:
    • lua中没有整数,都是浮点数运算,对应C中的double;
    • 新版本的lua是基于64位的整型,5.1暂不支持
    • 可以tonumber转换格式
  • string类型:
    • tostring转换格式
    • [[]]多行字符串赋值
    • 与C一样的转义
    • 通过..实现字符串的拼接,且可以直接拼接整型,注意不能拼接nil的变量
    • string.len(str), 获取字符串长度
    • string.sub(str,3,5),获取子字符串
    • local b,e = string.find(),查找,支持正则
    • string.gsub(),替换,不改变原值,返回替换后的值,支持正则
    • lua的下标是从1开始的,和matlab相同

Lua和C++的交互

调用C++中的函数, 通过堆栈交互

lua堆栈

包含头文件

extern "C" 
{
#include <lua.h> 
#include <lualib.h> 
#include <lauxlib.h> 
}

编译

g++ -o XX XX.cpp -llua -ldl

第一个例子

C++代码

#include <iostream> 
using namespace std;

extern "C" 
{
#include <lua.h> 
#include <lualib.h> 
#include <lauxlib.h> 
}

int main()
{
    lua_State *L = lua_open();
    luaopen_base(L);
    luaopen_string(L);
    luaopen_table(L);

    // 加载 lua 文件
    if ( luaL_loadfile(L, "main.lua") )
    {
        const char* error = lua_tostring(L, -1);
        cout << "lua load error: "<< error <<  endl;
        return -1;
    }

    // 执行 lua 文件
    if ( lua_pcall(L, 0, 0, 0) )
    {
        const char* error = lua_tostring(L, -1);
        cout << "lua call error: "<< error <<  endl;
        return -1;
    }

    getchar();

    return 0;
}

lua代码

print("hello word")

第二个列子

C++ code

#include <iostream>
using namespace std;

extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

// 开放函数给lua调用,并获取 Lua 传递的三个参数,普通参数
int CTest(lua_State* L)
{
    cout << "enter in CTest" << endl;
    size_t len;
    const char* name = lua_tolstring(L, 1, &len);
    cout << "Lua name: " <<  name << endl;

    int age = lua_tonumber(L, 2);
    cout << "Lua age: " << age << endl;

    bool bIs = lua_toboolean(L, 3);
    cout << "Lua bool: " << bIs <<  endl;
    return 0;
}

// 开放函数给lua调用,并获取 Lua 传递的表参数,按索引获取表参数
int CTestArray(lua_State* L)
{
    cout << "In CTestArray" << endl;
    int arrLen = luaL_getn(L,1); // 获取表的长度
    cout << "Table size: " << arrLen << endl;

    for (int i = 1; i <= arrLen; i++)
    {
        lua_pushnumber(L, i); // 2
        lua_gettable(L,1);    // pop index and push table[i]
        size_t iSize = 0;
        cout << lua_tolstring(L, -1, &iSize) << endl;
        lua_pop(L, 1);
    }

    return 0;
}

// 开放函数给lua调用,并获取 Lua 传递的表参数,按键值获取表参数
int CTestKeyVal(lua_State* L)
{
    cout << "In CTestKeyVal" << endl;
    lua_pushnil(L);
    while(lua_next(L,1) != 0)
    {
        cout << "key=" << lua_tostring(L,2) << ", ";
        cout << "value=" << lua_tostring(L,-1) << endl;
        lua_pop(L,1);
    }
    return 0;
}

// 开放函数给lua调用,并判断获取的参数是否是希望的类型
int CTestKeyVal_type(lua_State* L)
{
    // method1: type check
    luaL_checktype(L, 1, LUA_TTABLE);
    // method2: type check
    if (lua_type(L,2) != LUA_TNUMBER)
    {
        cout << "para 2 is not a number" << endl;
    }

    cout << "In CTestKeyVal" << endl;
    lua_getfield(L,1, "name");
    cout << "name: " <<lua_tostring(L,-1) <<endl;

    return 0;
}

// 开放函数给lua调用,C++ 返回一个普通的字符串
int CTestRetOne(lua_State* L)
{
    lua_pushstring(L, "return a string value"); 
    return 1;
}

// 开放函数给lua调用,C++ 返回一个表
int CTestRetTable(lua_State* L)
{
    lua_newtable(L);  // create new table

    lua_pushstring(L, "name");  // push key
    lua_pushstring(L, "xiaominmin");// pusn value
    lua_settable(L, -3);// write key and value into table

    lua_pushstring(L, "age");
    lua_pushnumber(L, 29);
    lua_settable(L, -3);

    return 1;
}


int main()
{
    lua_State *L = lua_open();
    luaopen_base(L);
    luaopen_string(L);  
    luaopen_table(L);

    // 注册开发的函数给lua
    lua_register(L, "CTest", CTest);
    lua_register(L, "CTestArray", CTestArray);
    lua_register(L, "CTestKeyVal", CTestKeyVal);
    lua_register(L, "CTestKeyVal_type", CTestKeyVal_type);
    lua_register(L, "CTestRetOne", CTestRetOne);
    lua_register(L, "CTestRetTable", CTestRetTable);

    if ( luaL_loadfile(L, "main.lua") )
    {
        const char* error = lua_tostring(L, -1);
        cout << "lua load error: "<< error <<  endl;
        return -1;
    }

    if ( lua_pcall(L, 0, 0, 0) )
    {
        const char* error = lua_tostring(L, -1);
        cout << "lua call error: "<< error <<  endl;
        return -1;
    }

    getchar();

    return 0;
}

lua code

-- 调用 CTest,并传递三个普通参数
CTest("Lua string",123, true)

-- 调用CTestArray,并传递带索引的表
local arr = {"A001","A002","A003", "A004"}
CTestArray(arr)

-- 调用 CTestKey,并传递键值表
local arr = {name="xiaoming", age="32",id="007"}
local size = "s108"
CTestKeyVal(arr)

-- 调用 CTestKey_type,并传递键值表,判读参数类型是否是期望的类型
local arr = {name="xiaoming", age="32",id="007"}
local size = "s108"
CTestKeyVal_type(arr, size)

-- 调用 CTestRetOne,并打印C++返回的值
local ret = CTestRetOne()
print ("ret = "..ret)

-- 调用 CTestRetTable,并打印C++的表
local ret = CTestRetTable()
print ("name = "..ret["name"])
print ("age = "..ret["age"])

第三个例子

C++ code

#include <iostream>
using namespace std;

extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}    

int main()
{
    lua_State *L = lua_open();

    // 打开需要用到的lua的库
    luaopen_base(L);            
    luaopen_string(L);  
    luaopen_table(L);   

    /* lua脚本启动之前,给lua脚本设置全局变量 */

    // 设置lua的全局变量,hello = test (key = value)
    lua_pushstring(L, "hello");
    lua_setglobal(L,"test");

    // 向 lua 中传递一个表,同例子2中的返回一个表给lua
    lua_newtable(L);               // create a table

    lua_pushstring(L, "name");     // key
    lua_pushstring(L, "xiaoming"); // value
    lua_settable(L, -3);
    lua_pushstring(L, "age");      // key
    lua_pushnumber(L, 20);         // value
    lua_settable(L, -3);

    lua_setglobal(L, "person");    // write value to table

    if ( luaL_loadfile(L, "main.lua") )
    {
        const char* error = lua_tostring(L, -1);
        cout << "lua load error: "<< error <<  endl;
        return -1;
    }

    if ( lua_pcall(L, 0, 0, 0) )
    {
        const char* error = lua_tostring(L, -1);
        cout << "lua call error: "<< error <<  endl;
        return -1;
    }

    // C++ 获取lua中的普通全局变量
    lua_getglobal(L, "width");
    int width = lua_tonumber(L, -1);
    lua_pop(L, 1); // 注意要清lua堆栈
    cout << "width: " << width << endl;

    // C++ 获取lua中的表全局变量
    lua_getglobal(L, "conf");
    lua_getfield(L, -1, "titlename");
    cout << "titlename: " << lua_tostring(L,-1) <<  endl;
    lua_pop(L,1);

    lua_getfield(L, -1, "height");
    cout << "height: " << lua_tonumber(L, -1) <<  endl;
    lua_pop(L, 1);

    // C++ 调用 lua中的名为 event的函数,无参数无返回值
    cout<< "stack top is " << lua_gettop(L) << endl;
    lua_getglobal(L, "event");
    if ( lua_pcall(L, 0, 0, 0) != 0)// 无参数,无返回值,无回调函数
    {
        cout << "call event failed " << lua_tostring(L, -1)<< endl;
        lua_pop(L, 1);
    }
    cout<< "stack top is " << lua_gettop(L) << endl;

    // C++ 调用 lua中的名为 ferror和event2 的函数,有参数有返回值
    cout<< "stack top is " << lua_gettop(L) << endl;
    int errfun = lua_gettop(L);
    lua_getglobal(L, "ferror");
    errfun++;
    lua_getglobal(L, "event2");
    lua_pushstring(L, "key");
    if ( lua_pcall(L, 1, 1, errfun) != 0)// 一个参数,一个返回值,回调函数errfun
    {
        cout << "call event failed " << lua_tostring(L, -1)<< endl;
        lua_pop(L, 1);
    }
    else
    {
        cout << "Lua return: " << lua_tostring(L, -1) << endl;
        lua_pop(L, 1);
    }
    lua_pop(L, 1);
    cout<< "stack top is " << lua_gettop(L) << endl;

    // C++ 调用 lua中的名为 ferror和event3 的函数,有表参数和表返回值
    cout<< "stack top is " << lua_gettop(L) << endl;
    int errfun1 = lua_gettop(L);
    lua_getglobal(L, "ferror");
    errfun1++;
    lua_getglobal(L, "event3");
    lua_pushstring(L, "key");
    lua_newtable(L);
    lua_pushstring(L,"name");
    lua_pushstring(L, "xiaomingming");
    lua_settable(L, -3);

    if ( lua_pcall(L, 2, 1, errfun) != 0) // 两个参数,一个返回值,回调函数errfun
    {
        cout << "call event failed " << lua_tostring(L, -1)<< endl;
        lua_pop(L, 1);
    }
    else
    {
        //cout << "Lua return: " << lua_tostring(L, -1) << endl;
        lua_getfield(L, -1, "id");
        cout << "Lua return id: " << lua_tonumber(L, -1) << endl;
        lua_pop(L,1);

        lua_getfield(L, -1, "age");
        cout << "lua return age: " << lua_tonumber(L, -1) << endl;
        lua_pop(L, 1);

        lua_pop(L, 1);
    }
    lua_pop(L, 1);
    cout<< "stack top is " << lua_gettop(L) << endl;

    lua_close(L);
    return 0;
}

lua code

-- Lua的全局变量,供C++使用
width=1920
conf = 
{
    titlename = "first lua",
    height = 1080
}

-- 打印C++设置的全局变量,普通变量
print("C++ test: ".. test)

-- 打印C++设置的全局变量,表
for k,v in pairs(person) do
    print(k.."=>"..v)
end

-- C++ 调用 lua函数并传递普通参数,lua函数有返回值
function ferror(e)
    print("lua error: "..e)
    return "lua change error"
end

-- C++ 调用 lua函数,无参数,lua函数无返回值
function event()
    print("C++ call lua function.") 
end

-- C++ 调用 lua函数并传递普通参数,lua函数有返回值
function event2(e)
    print("C++ call lua function event 1.")
    print(e)
    return "Lua renturn a string"
end

-- C++ 调用 lua函数并传递表参数,lua函数返回表参数
function event3(e, obj)
    print("C++ call lua function event 1.")
    print(e)
    print (obj.name)

    local re = {id=123, age=29}
    return re
end

猜你喜欢

转载自blog.csdn.net/guoxiaojie_415/article/details/70447917
今日推荐