1、Lua和C++交互

1、lua和c++交互机制是基于一个虚拟栈,C++和lua之间的所有数据交互都通过这个虚拟栈来完成,无论何时C++想从lua中调用一个值,被请求的值将会被压入栈,C++想要传递一个值给Lua,首选将整个值压栈,然后就可以在Lua中调用。 2、lua中提供正向和反向索引,区别在于证书永远是栈底,负数永远是栈顶。

Lua与C++交互_Lua

在这里插入图片描述

2、基础练习

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

#include <iostream>
#include<string.h>
usingnamespace 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);
return0;
}

Lua与C++交互_Lua_02

在这里插入图片描述

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

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

函数说明:

1、函数用于将Lua脚本加载到Lua虚拟机中并进行编译
luaL_loadbuffer(L,s,sz,n)
    lua_State *L:Lua状态对象,表示Lua虚拟机的运行实例。
constchar*buff:指向Lua脚本内容的字符串。
size_t sz:Lua脚本内容的长度。
constchar*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,constchar*name)
    lua_State *L:Lua状态对象,表示Lua虚拟机的运行实例。
constchar*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、获取脚本中的返回值

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

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

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

charconst*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);
return0;
}

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>
}
charconst*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()
*/

charconst*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
charconst*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);
}
return0;
}

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)
return0;

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);
return1;
}
return0;
}

charconst*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);
return0;
}

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

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

#include <cstdio>
#include<cstring>
#include<cmath>
#include<new>
extern"C"{
#include<lua.h>
#include<lualib.h>
#include<lauxlib.h>
}
charconst*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())
)";

classGameObject{
private:
u_int32_t _id;
public:
staticsize_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_tGameObject::registy_value =0;

intGameObject_equal(lua_State *state){
int arg_count = lua_gettop(state);
if(arg_count!=2){
return0;
}

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);
return1;
}
return0;
}

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

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);
return1;
}

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);
return0;
}