[✔️]c++和lua相互调用

简介: [✔️]c++和lua相互调用

lua源码


lua官网下载lua源码,自己学习lua和c++相互调用的例子


image.png


以下2个文件不需要参与编译,原因是他们是bin文件的源代码,都有Main入口


lua.c


image.png


luac.c


image.png


加载lua文件


lua_State* L = luaL_newstate();
luaL_loadfile(L, "main.lua");
lua_pcall(L,0,0,0);
// luaL_dofile(L, "main.lua");
lua_close(L);


  • dofile和loadfile的区别:


#define luaL_dofile(L, fn)  (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_loadfile(L,f)  luaL_loadfilex(L,f,NULL)


lua调用c++函数(注册全局函数)


注册函数类型:


typedef int (*lua_CFunction) (lua_State *L);


没有返回值的


  • lua


print("cpp call me");


  • cpp


int print(lua_State* L){
    if (lua_isstring(L, -1))
    {
        cout << lua_tostring(L, -1) << endl;
    }
    return 0;
}
void main(){
    lua_State* L = luaL_newstate();
    lua_register(L, "print", print); 
    luaL_dofile(L, "test.lua");
    lua_close(L);
}


返回int,string基础类型


  • lua


local sum, mul = add(100, 20);
print("sum: " .. sum);
print("mul:" .. mul)


  • cpp


int add(lua_State* L){
    // 参数是按照顺序依次压入栈里面
    double a = lua_tonumber(L, -1); 
    double b = lua_tonumber(L, -2);
    lua_pushnumber(L, a + b);
    lua_pushnumber(L, a * b);
    return 2;// 返回的参数个数
}
void main(){
    lua_State* L = luaL_newstate();
    lua_register(L, "add", add); 
    luaL_dofile(L, "test.lua");
    lua_close(L);
}


返回table类型


  • lua


local t = returnTable();
for i, v in pairs(t) do
    print("key:" .. i .. ",value:" .. v)
end


  • cpp


void returnTable(){
    lua_newtable(L);// len1
    lua_pushstring(L, "age");// len2
    lua_pushstring(L, "120");// len3
    lua_rawset(L, -3);// len1
    return 1; // 此时堆栈里面就剩下newtable了
}
void main(){
    lua_State* L = luaL_newstate();
    luaopen_base(L); // 注册了一些内置的基础函数:ipairs、pairs、print
    lua_register(L, "returnTable", returnTable); 
    luaL_dofile(L, "test.lua");
    lua_close(L);
}


遇到的一个报错


attempt to call a nil value (global 'pairs')


很明显,提示找不到pairs=nil,难道pairs不是lua的关键字?

是的,这是lua的内置基础函数


cpp调用lua的变量


一般我们不需要调用lua的函数,大部分情况都是lua调用c++的实现


  • lua


str="string"
int=100


  • cpp


lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaVar.lua");
{
    // 读取全局变量,并将其放入栈顶
    lua_getglobal(L, "str");
    // 从栈顶取出字符串数据
    cout << "str=" << luaL_checkstring(L,-1)  << endl;
    lua_getglobal(L, "int");
    cout << "int=" << luaL_checkinteger(L, -1) << endl;
    cout << "len=" << lua_gettop(L) << endl; // 此时栈的大小为2
}
lua_close(L);


lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaVar.lua");
{
    lua_getglobal(L, "str");
    lua_getglobal(L, "int");
    // 注意读取的顺序
    cout << "str=" << luaL_checkstring(L, 1) << endl;
    cout << "int=" << luaL_checkinteger(L, 2) << endl;
    cout << "len=" << lua_gettop(L) << endl; // 此时栈的大小为2
}
lua_close(L);


从以上2个例子中可以看出,lua_getglobal会依次将查找到的值放入栈顶,使用的时候需要栈的顺序


关于luaL_check*的api:


LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) {
  int isnum;
  lua_Integer d = lua_tointegerx(L, arg, &isnum);
  if (l_unlikely(!isnum)) {
    interror(L, arg);
  }
  return d;
}
static void interror (lua_State *L, int arg) {
  if (lua_isnumber(L, arg))
    luaL_argerror(L, arg, "number has no integer representation");
  else
    tag_error(L, arg, LUA_TNUMBER);
}


lua_is*这类的函数可以判断栈中的数据类型,但是需要注意int->string的隐形转换。


cpp调用lua的table


  • lua


tbl = {
    name = "lua",
    100,
    {
        id = 10,
    }
}


  • cpp通过key获取值


lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaTable.lua");
lua_getglobal(L, "tbl"); // len=1
lua_getfield(L, -1, "name");// 此时tbl在栈顶,所以第二个参数是-1, len=2
cout << "tbl.name=" << luaL_checkstring(L, -1) << endl;
lua_close(L);


lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaTable.lua");
lua_getglobal(L, "tbl"); // len=1
lua_pushstring(L, "11");// 这个是干扰项,len=2
lua_pushstring(L, "name");// len=3
// 从栈顶取出一个元素(name)并且返回把查找到的值压入栈顶
lua_gettable(L, 1); // len=3
cout << lua_tostring(L, -1);
lua_close(L);


  • cpp获取无序的值


lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaTable.lua");
lua_getglobal(L, "tbl"); // len=1
// -1表示tbl在栈顶, 1表示取tbl[1]
lua_rawgeti(L, -1, 1);// len=2
// 将tbl[1]的值放在了栈顶,因为tbl[1]=100
cout << "tbl[1]=" << lua_tointeger(L, -1) << endl;
lua_pop(L,1); // 弹出tbl[1]的值,len=1
// 获取嵌套的table
lua_rawgeti(L,-1,2);// 此时栈顶是tbl,直接获取tbl[2]元素,len=2
lua_getfield(L,-1,"id");//将id的值放在栈顶,len=3
cout << lua_tointeger(L, -1);
lua_close(L);


cpp调用lua的函数


  • lua


function add(a, b)
    return a + b;
end


  • cpp


lua_State* L = luaL_newstate();
luaL_dofile(L, "cppCallLuaFunction.lua");
lua_getglobal(L, "add");// len=1
lua_pushnumber(L, 10);// len=2
lua_pushnumber(L, 20);// len=3
// 2表示参数数量,1表示返回值个数,0表示错误处理函数在栈中的索引值,压入结果前会弹出函数和参数
// 弹出函数地址和所有参数,并将返回值压入栈顶
int ret = lua_pcall(L, 2, 1, 0); // len=1
cout << "add result is: " << luaL_checkinteger(L, -1) << endl;
lua_close(L);


lua栈


  • 特点:先进后出


  • 正数索引1永远表示栈底,负数索引-1永远表示栈顶**


image.png

lua_gettop(L); // 获取当前lua栈的大小
lua_pop(L, -1);// 弹出栈顶元素,-1弹出所有,>1弹出指定数量的元素


CPP栈操作


void test1(){
    lua_State* L = luaL_newstate();
    lua_pushstring(L, "i am string");
    lua_pushnumber(L, 100);
    if (lua_isstring(L, 1))
    {
        cout << lua_tostring(L, 1) << endl;
    }
    if (lua_isnumber(L, 2))
    {
        cout << lua_tonumber(L, 2) << endl;
    }
    lua_close(L);
}


堆栈情况如下:


image.png

目录
相关文章
|
6月前
|
存储 编译器 C语言
C与C++之间相互调用的基本方法
C与C++之间相互调用的基本方法
125 1
|
编译器 测试技术 C语言
C与C++之间的相互调用及函数区别
最近项目需要使用google test(以下简称为gtest)作为单元测试框架,但是项目本身过于庞大,main函数无从找起,需要将gtest框架编译成静态库使用。因为项目本身是通过纯c语言编写,而gtest则是一个c++编写的测试框架,其中必然涉及c与c++之间的相互调用。 注意,本文的前提是,c代码采用gcc等c语言编译器编译c代码,采用g++等c++编译器编译c++代码,如果c和c++代码统一使用g++编译,大部分情况是可以实现两者代码相互调用的。以下为踩坑过程的总结o_O||。 c与c++的函数区别 要了解两者之间如何实现相互调用,必须先了解c与c++之间的函数有什么不同。 c+
127 0
|
Ubuntu 云计算 C++
C++与lua的结合,LuaBridge的使用及遇到的坑
C++与lua的结合,LuaBridge的使用及遇到的坑
|
C++
[✔️]lua中的function,在c++进行callback
[✔️]lua中的function,在c++进行callback
184 0
|
C++
[✔️]c++返回2个值给lua,tolua如何处理c++函数重载
[✔️]c++返回2个值给lua,tolua如何处理c++函数重载
134 0
|
XML 传感器 关系型数据库
c/c++和lua的交互使用分享
c/c++和lua的交互使用分享
506 0
c/c++和lua的交互使用分享
|
C# 图形学 C++
原生实现C#和Lua相互调用-Unity3D可用【下】
1. 编译Windows下使用的DLL文件 使用VS2015创建一个空的动态链接库项目,删除里面默认创建的几个文件(如果想自定义拓展可用保留),然后把Lua的源码拷贝进来,添加到项目工程中,编译宏需要配置LUA_BUILD_AS_DLL和_CRT_SECURE_NO_WARNINGS。然后就可以编译x86和x64的DLL动态库,整体步骤简单易操作。
361 0
|
C# 图形学 Windows
原生实现C#和Lua相互调用-Unity3D可用【中】
1. 编译Windows下使用的DLL文件 使用VS2015创建一个空的动态链接库项目,删除里面默认创建的几个文件(如果想自定义拓展可用保留),然后把Lua的源码拷贝进来,添加到项目工程中,编译宏需要配置LUA_BUILD_AS_DLL和_CRT_SECURE_NO_WARNINGS。然后就可以编译x86和x64的DLL动态库,整体步骤简单易操作。
198 0
|
API C# Android开发
原生实现C#和Lua相互调用-Unity3D可用【上】
1. 编译Windows下使用的DLL文件 使用VS2015创建一个空的动态链接库项目,删除里面默认创建的几个文件(如果想自定义拓展可用保留),然后把Lua的源码拷贝进来,添加到项目工程中,编译宏需要配置LUA_BUILD_AS_DLL和_CRT_SECURE_NO_WARNINGS。然后就可以编译x86和x64的DLL动态库,整体步骤简单易操作。
318 0
|
C语言 C++ 编译器
C语言与C++语言相互调用
C语言与C++语言相互调用 1 C++调用C中的函数   1.1 C++调用C中的函数(正确使用)   1、案例源文件组成                                               图1   2、math模块包含文件   1)源文件math.
1153 0