Lua与C++交互

文章目录

1、Lua和C++交互

1、lua和c++交互机制是基于一个虚拟栈,C++和lua之间的所有数据交互都通过这个虚拟栈来完成,无论何时C++想从lua中调用一个值,被请求的值将会被压入栈,C++想要传递一个值给Lua,首选将整个值压栈,然后就可以在Lua中调用。

2、lua中提供正向和反向索引,区别在于证书永远是栈底,负数永远是栈顶。

2、基础练习

编译指令:g++ test.cpp -o test -llua -ldl

lua 复制代码
#include <iostream>  
#include <string.h>  
using namespace std;
 
extern "C"
{
#include "lua.h"  
#include "lauxlib.h"  
#include "lualib.h"  
}

// g++ test.cpp -o test  -llua -ldl
int main()
{
	//1.创建一个state  
	// luaL_newstate返回一个指向堆栈的指针
	lua_State *L = luaL_newstate();
 
	//2.入栈操作  
	lua_pushstring(L, "hello world");
	lua_pushnumber(L, 200);
 
	//3.取值操作  
	if (lua_isstring(L, 1)) {             //判断是否可以转为string  
		cout << lua_tostring(L, 1) << endl;  //转为string并返回  
	}
	if (lua_isnumber(L, 2)) {
		cout << lua_tonumber(L, 2) << endl;
	}
 
	//4.关闭state  
	lua_close(L);
	return 0;
}

2.1、加载Lua脚本并传递参数

编译指令:g++ test.cpp -o test -llua -ldl

lua 复制代码
函数说明:

1、函数用于将Lua脚本加载到Lua虚拟机中并进行编译
luaL_loadbuffer(L,s,sz,n)
	lua_State *L:Lua状态对象,表示Lua虚拟机的运行实例。
	const char *buff:指向Lua脚本内容的字符串。
	size_t sz:Lua脚本内容的长度。
	const char *name:可选参数,用于给脚本设置一个名称,便于调试和错误消息的输出。
	返回值:
		不为0表示有错误

2、函数用于调用Lua函数并处理其执行过程中可能发生的错误
lua_pcall(L,n,r,f)
	lua_State *L:Lua状态对象,表示Lua虚拟机的运行实例。
	int nargs:传递给Lua函数的参数数量。
	int nresults:期望的返回值数量。
	int errfunc:错误处理函数在调用栈中的索引。
	返回值:
		不为0表示有错误

3、函数用于从全局环境中获取一个全局变量,并将其值压入Lua栈顶
int lua_getglobal(lua_State *L, const char *name)
	lua_State *L:Lua状态对象,表示Lua虚拟机的运行实例。
	const char *name:要获取的全局变量的名称。

4、函数用于将一个数字(lua_Number类型)压入Lua栈顶
void lua_pushnumber(lua_State *L, lua_Number n)
	lua_State *L:Lua状态对象,表示Lua虚拟机的运行实例。
	lua_Number n:要压入栈的数字。

执行流程:

1、加载script脚本加载到lua虚拟机中

2、将脚本中的my_pow函数,压入到栈顶

3、压入my_pow需要的两个参数

4、执行脚本

5、获取脚本中的返回值

lua 复制代码
#include <cstdio>
#include <cstring>
#include <cmath>
#include <new>
extern "C" {
    #include <lua.h>
    #include <lualib.h>
    #include <lauxlib.h>
}

char const *script = R"(
function hello()
    print('hello world')
end

function my_pow(x,y)
    return x^y
end
)";

char const *script_1 = R"(
    pkg.hello()
)";

int main()
{
    /*
        加载脚本并传递参数
    */
    
    // 创建lua虚拟机,创建虚拟栈
    lua_State *state = luaL_newstate();
    // 打开lua标准库,以便正常使用lua api
    luaL_openlibs(state);
    {
        // 将lua脚本加载到虚拟机中,并编译
        auto rst = luaL_loadbuffer(state,script,strlen(script),"hello");
        // 判断是否加载成功
        if(rst !=0 ){
            if(lua_isstring(state,-1)){
                auto msg = lua_tostring(state,-1);
                printf("load script faile:%s\n",msg);
                lua_pop(state,-1);
            }
            return -1;
        }
        // 执行加载并编译的Lua脚本
        if(lua_pcall(state,0,0,0)){
            if(lua_isstring(state,-1)){
                auto msg = lua_tostring(state,-1);
                printf("load script faile:%s",msg);
                lua_pop(state,-1);
            }
        }

        // 从全局环境中获取一个my_pow函数压入到栈顶
        lua_getglobal(state,"my_pow");
        // 判断栈顶是不是一个函数,要是不是表示没有找到
        if(!lua_isfunction(state,-1)){
            printf("function  named my_pow not function\n");
            return -1;
        }
        // 将数字参数压入Lua栈中
        lua_pushnumber(state,2);
        lua_pushnumber(state,8);
        rst = lua_pcall(state,2,1,0);
        if(rst !=0 ){
            if(lua_isstring(state,-1)){
                auto msg = lua_tostring(state,-1);
                printf("load script faile:%s\n",msg);
                lua_pop(state,-1);
            }
            return -1;
        }
        if(lua_isnumber(state,-1)){
            lua_Number val = lua_tonumber(state,-1);
            printf("%lf\n",val);
        }
    }
    lua_close(state);
    return 0;
}

2.2、加载脚本到stable(包)

编译命令: g++ main.cpp -o main -llua -ldl

lua 复制代码
#include <cstdio>
#include <cstring>
#include <cmath>
#include <new>
extern "C" {
    #include <lua.h>
    #include <lualib.h>
    #include <lauxlib.h>
}
char const *script = R"(
function hello()
    print('hello world')
end

function my_pow(x,y)
    return x^y
end
)";

/*   
	_G = {
    "helloworld" = function print("hello world")
    }
    _G = {
        "pkg" = {
            "helloworld" = function print("hello world")
        }
    }

    pkg.helloworld()
*/
    
char const *script_1 = R"(
    pkg.hello()
)";

int main()
{
    /*
        加载脚本到stable(包)
        1、生成chunk push到栈顶
        2、创建table,设置给_G表,_G["pkg"] = {}
        3、给这个table设置元表,元表继承_G的访问域(__index)
        4、执行code chunk
    */
    lua_State *state = luaL_newstate();
    luaL_openlibs(state);
    {
        auto rst = luaL_loadbuffer(state,script,strlen(script),"helloworld");
        if(rst != 0){
            if(lua_isstring(state,-1)){
                auto msg = lua_tostring(state,-1);
                printf("load script faile:%s\n",msg);
                lua_pop(state,1);
            }
            return -1;
        }
        
        // 取出_G表
        lua_getglobal(state,"_G");
        if(lua_istable(state,-1)){  // chunk _G
            lua_newtable(state);    // 创建表 chunk _G new_stable
            lua_pushstring(state,"pkg"); // chunk _G new_stable pkg
            lua_pushvalue(state,-2); // chunk _G new_stable pkg new_stable
            lua_rawset(state,-4);   // chunk _G new_stable
            char const *upvalueName = lua_setupvalue(state,-3,1); // chunk _G
            lua_newtable(state);    // chunk _G metastable
            lua_pushstring(state,"__index");    // chunk _G metastable "__index"
            lua_pushvalue(state,-3); // chunk _G metastable "__index" _G
            lua_rawset(state,-3);   // chunk _G metastable
            lua_pushstring(state,"pkg");
            lua_rawget(state,-3);   // chunk _G metastable "pkg"(table)
            lua_pushvalue(state,-2);    // chunk _G metastable pkg(table) metastable
            lua_setmetatable(state,-2); // chunk _G metastable pkg(stable)
            lua_pop(state,3);   // chunk
        }
        // 执行chunk
        if(lua_pcall(state,0,0,0)){
            if(lua_isstring(state,-1)){
                auto msg = lua_tostring(state,-1);
                printf("call function chunk failed:%s\n",msg);
                lua_pop(state,1);
            }
        }

        // 加载script_1
        rst = luaL_loadbuffer(state,script_1,strlen(script_1),"script_1");
        if(rst != 0){
            if(lua_isstring(state,-1)){
                auto msg = lua_tostring(state,-1);
                printf("load script failed:%s\n",msg);
                lua_pop(state,1);
            }
            return -1;
        }

        if(lua_pcall(state,0,0,0)){
            if(lua_isstring(state,-1)){
                auto msg = lua_tostring(state,-1);
                printf("call function chunk failed:%s\n",msg);
                lua_pop(state,1);
            }
        }
        lua_close(state);
    }
    return 0;
}

2.3、Lua调用c语言接口

lua 复制代码
#include <cstdio>
#include <cstring>
#include <cmath>
#include <new>
extern "C" {
    #include <lua.h>
    #include <lualib.h>
    #include <lauxlib.h>
}

int pow_from_c(lua_State *L)
{
    int param_count = lua_gettop(L);
    if(param_count != 2)
        return 0;
    
    if(lua_isinteger(L,1) && lua_isinteger(L,2)){
        auto x = lua_tointeger(L,1);
        auto y = lua_tointeger(L,2);
        int rst = (int)pow(x,y);
        lua_pushinteger(L,rst);
        return 1;
    }
    return 0;
}

char const *script_2 = R"(
    local val = pow_from_c(2,3)
    print(val)
)";
int main()
{
    // lua调用c语言接口
    lua_State *state = luaL_newstate();
    luaL_openlibs(state);
    {
        /*
            "_G" = {
                "pow_from_c" = pow_from_c
            }
        */
        lua_getglobal(state,"_G");
        lua_pushstring(state,"pow_from_c");
        lua_pushcclosure(state,pow_from_c,0);    // _G "pow_from_c"; closure
        lua_rawset(state,-3);   // _G
        lua_pop(state,1);   // _G
    }

    auto rst = luaL_loadbuffer(state,script_2,strlen(script_2),"script_2");
    if(rst != 0){
        if(lua_isstring(state,-1)){
            auto msg = lua_tostring(state,-1);
            printf("load script faile:%s\n",msg);
            lua_pop(state,1);
        }
        return -1;
    }

    if(lua_pcall(state,0,0,0)){
        if(lua_isstring(state,-1)){
            auto msg = lua_tostring(state,-1);
            printf("call function chunk failed:%s\n",msg);
            lua_pop(state,1);
        }
    }
    lua_close(state);
    return 0;
}

2.4、Lua实现面向对象

lua 复制代码
local anial_matestable = {
    __index = {
        walk = function (self)
            print(self,"我是walk")
        end,
        eat = function (self)
            print(self,"eat.")
        end,
    },

    __newindex = function (object,key,value)
        print("assigned "..value.."named "..key.."but not really")
    end,
}

function newobject()
    local objs = {name = "xxxx"}
    setmetatable(objs,anial_matestable)
    return objs
end

local obj = newobject()
obj.eat()
obj.walk()
obj.name = "abc"
obj.id = 0

2.5、向脚本中注册c++的类

lua 复制代码
#include <cstdio>
#include <cstring>
#include <cmath>
#include <new>
extern "C" {
    #include <lua.h>
    #include <lualib.h>
    #include <lauxlib.h>
}
char const *script_3 = R"(
    local obj_1 = create_game_object(1);
    local obj_2 = create_game_object(1);
    local obj_3 = create_game_object(2);
    local rst1 = obj_1:equal(obj_2)
    local rst2 = obj_1:equal(obj_3)
    print(rst1,";",rst2)
    print(""..obj_1:id())
)";

class GameObject{
private:
    u_int32_t _id;
public:
    static size_t registy_value;
public:
    GameObject(u_int32_t id):_id(id)
    {}
    u_int32_t id()const{
        return _id;
    }
    bool equal(GameObject *obj){
        return _id == obj->id();
    }
};
size_t GameObject::registy_value = 0;

int GameObject_equal(lua_State *state){
    int arg_count = lua_gettop(state);
    if(arg_count!=2){
        return 0;
    }

    if(lua_isuserdata(state,1) && lua_isuserdata(state,2)){
        void *userdata_self = lua_touserdata(state,1);
        void *userdata_that = lua_touserdata(state,2);
        GameObject *obj1 = (GameObject*)userdata_self;
        GameObject *obj2 = (GameObject*)userdata_that;
        auto rst = obj1->equal(obj2);
        lua_pushboolean(state,rst);
        return 1;
    }
    return 0;
}

int GameObject_id(lua_State* state){
    GameObject *this_obj = (GameObject*)lua_touserdata(state,1);
    auto rst = this_obj->id();
    lua_pushinteger(state,rst);
    return 1;
}

int create_game_object(lua_State* state){
    auto id = lua_tointeger(state,1);
    void *p = lua_newuserdata(state,sizeof(GameObject));
    GameObject *obj = new(p)GameObject(id);
    lua_rawgetp(state,LUA_REGISTRYINDEX,&GameObject::registy_value);
    lua_setmetatable(state,-2);
    return 1;
}

int main()
{
    // 怎么向脚本中注册c++的类
    // 使用userdata
    /*
        userdata:{
            metadata:{
                __index = {
                    equal = function(){},
                    id = function(){},
                }
            }
        }
    */
    lua_State *state = luaL_newstate();
    luaL_openlibs(state);
    {
        lua_getglobal(state,"_G");
        lua_pushstring(state,"create_game_object");
        lua_pushcclosure(state,create_game_object,0);
        lua_rawset(state,-3);
        lua_pop(state,1);

        lua_newtable(state);
        lua_pushstring(state,"__index");
        lua_newtable(state);
        lua_pushstring(state,"equal");
        lua_pushcclosure(state,GameObject_equal,0);
        lua_rawset(state,-3);
        lua_pushstring(state,"id");
        lua_pushcclosure(state,GameObject_id,0);
        lua_rawset(state,-3);
        lua_rawset(state,-3);

        lua_rawsetp(state,LUA_REGISTRYINDEX,&GameObject::registy_value);
        auto rst = luaL_loadbuffer(state,script_3,strlen(script_3),"oop");
        if(rst != 0){
            if(lua_isstring(state,-1)){
                auto msg = lua_tostring(state,-1);
                printf("load script failed:%s\n",msg);
                lua_pop(state,1);
            }
            return -1;
        }
        // 执行
        if(lua_pcall(state,0,0,0)){
            if(lua_isstring(state,-1)){
                auto msg = lua_tostring(state,-1);
                printf("load script failed:%s\n",msg);
                lua_pop(state,1);
            }
        }
    }
    lua_close(state);
    return 0;
}
相关推荐
fangzhanpeng1686 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心8 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552714 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552715 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝16 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552716 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552717 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552719 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552719 天前
Java I/O核心操作实战
人工智能·1024程序员节
u01030552720 天前
ArrayList操作详解与实战应用
人工智能·1024程序员节