• 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

    #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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述

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

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

    函数说明:
    
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    执行流程:
    1、加载script脚本加载到lua虚拟机
    2、将脚本中的my_pow函数,压入到栈顶
    3、压入my_pow需要的两个参数
    4、执行脚本
    5、获取脚本中的返回值

    #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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    2.2、加载脚本到stable(包)

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

    #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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107

    2.3、Lua调用c语言接口

    #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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    2.4、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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

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

    #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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
  • 相关阅读:
    day03-前端配置、跨域问题、后端数据库迁移、后台主页功能、后台管理
    MySQL增删查改(进阶2)
    hive 慢sql 查询
    模型UV纹理设置工具
    vue3+ts+uniapp实现小程序端input获取焦点计算上推页面距离
    【模型训练】YOLOv7反光衣检测
    【Linux】多路IO复用技术③——epoll详解&如何使用epoll模型实现简易的一对多服务器(附图解与代码实现)
    Python 爬虫实战
    Linux sed工具的使用
    Unity-协同程序原理
  • 原文地址:https://blog.csdn.net/weixin_45715405/article/details/134010903