精华内容
下载资源
问答
  • C++与Lua交互

    2018-10-17 20:46:04
    C++与Lua交互环境搭建1.C++调用lua2.lua调用C++ lua作为一门动态语言,可用来做配置和经常变化的业务功能,很方便的实现热更新的效果。同时lua作为一门胶水语言,配合强大的C++作逻辑支撑,程序性能高、开发效率快...


    lua作为一门动态语言,可用来当做配置文件和实现经常变化的业务功能,很方便的实现热更新。同时lua作为一门胶水语言,配合强大的C++作逻辑支撑,程序性能高、开发效率快,犹如珠帘合璧,所向无敌。C++与lua的交互主要通过lua的虚拟栈实现,本文不打算深入讲解其中原理,只是简单记录下C++与lua的调用关系。

    环境搭建

    mac、linux系统
    $ wget http://www.lua.org/ftp/lua-5.2.3.tar.gz
    $ tar zxf lua-5.2.3.tar.gz
    $ cd lua-5.2.3
    $ make posix
    $ make posix install

    windows系统:略

    1.C++调用lua

    假如当前文件夹为demo1。先创建一个lua脚本, 路径为:demo1/scripts/test.lua。脚本内容如下:

    -- 全局变量
    id = 666
    title = "this is a test"
    array = {r = 2,g = 3,b = 4}
    array_1d = {2,5,26,8}
    array_2d = {{2,5},{15,18},{25,26,28},{0,5,4}}
    
    -- 无参函数
    function ruler_func()
        print("[lua]: this is some thing need to tell you!!!");
    end
    
    -- 有参函数
    function add_func(a,b)
        print("[lua]: a("..a..") + b("..b..") ="..a+b.."!");
        return a+b;
    end
    

    在当前文件夹创建C++文件demo1/demo.cpp,用来测试调用lua脚本。文件内容如下:

    /*
     *  demo.cpp 
     *  demo
     *
     *  Created by Jevstein on 2018/10/16 11:30.
     *  Copyright @ 2018year Jevstein. All rights reserved.
     *
     */
    
    #include <iostream>
    #include <string>
    using namespace std;
    
    //0.包含lua头文件
    extern "C"
    {
    	#include <lua.h>
    	#include <lauxlib.h>
    	#include <lualib.h>
    }
    
    void call_lua_test()
    {
    	//1.创建lua环境
    	lua_State *L = luaL_newstate(); //lua_open()
    	if (L == NULL)
    	{
    		std::cout << "[C++]: Failed to create Lua State!" << std::endl;
    		return;
    	}
    
    	//2.加载库
    	luaL_openlibs(L);//加载终端输出打印信息库,届时可看到lua的print信息
    
    	//3.加载lua脚本
    	const std::string script = "./scripts/test.lua";
    	int ret = luaL_dofile(L, script.c_str());
    	if (ret != 0)
    	{
    		std::cout << "[C++]: Failed to load lua !" << std::endl;
    		return;
    	}
    
    	//4.调用脚本内容: 变量、函数等
    	//     为简化代码,以下可以对其封装,如:
    	//  bool load_file(string str);		//加载文件
    	//  string load_string(string str);	//读取string变量
    	//  int load_integer(string str);	//读取int变量
    	//  double load_double(string str);	//读取double变量
    	//  bool load_boolean(string str);	//读取bool变量
    	//  bool load_map(const char* name, const int number, string str[], double array_list[], int type = 0);	//读取map
    	//  bool load_array(const char* name, int*& array);	//读取array
    	{//4.1.全局变量
    		std::cout << "[C++]: 1.Get variable !" << std::endl;
    
    		lua_getglobal(L, "id");//变量名称
    		if (lua_isnumber(L, -1))
    		{
    			int id = 0;
    			std::cout << "[C++]: The result is id=" << (int)lua_tointeger(L, -1) << endl;
    		}
    	}
    	{//4.2.无参函数
    		std::cout << "[C++]: 2.Call ruler_func() !" << std::endl;
    		lua_getglobal(L, "ruler_func");		//脚本函数名: ruler_func
    		lua_pcall(L, 0, 0, 0);				//用保护模式调用lua函数:入参个数为0、出参个数为0、无自定义错误处理
    	}
    	{//4.3.有参函数
    		int number1 = 100;
    		int number2 = 200;
    		printf("[C++]: 3.Call add_func(%d, %d)!\n", number1, number2);
    		lua_getglobal(L, "add_func");		//脚本函数名: add_func
    		lua_pushnumber(L, number1);			//参数1入参: 100
    		lua_pushnumber(L, number2);			//参数2入参: 200
    		lua_pcall(L, 2, 1, 0);				//函数有两个入参,一个出参,所以函数形式为add(a,b)
    
    		//获得返回值: 单回值情况下调用完成后lua会把结果放到栈顶,多返回值时,按照规则存放
    		if (lua_isnumber(L, -1) != 0)
    		{
    			std::cout << "[C++]: The result is :" << lua_tonumber(L, -1) << endl;
    		}
    	}
    
    	//5.销毁lua环境
    	lua_close(L);
    }
    
    int main()
    {
    	std::cout << "--------- sample: C++ call Lua --------- " << std::endl;
    	call_lua_test();
    	std::cout << "--------- the end --------- " << std::endl;
    
    	return 0;
    }
    

    linux下,使用g++编译:
    $ g++ -o demo *.cpp -llua -ldl

    执行demo,结果如下:
    在这里插入图片描述

    2.lua调用C++

    lua调用C/C++,需要将C/C++编译成动态库。假如当前文件夹为demo2。先创建C++文件, 路径为:demo2/lcpp/MyLuaMath.h和demo2/lcpp/MyLuaMath.cpp。文件内容如下:
    C++头文件:

    /*
     *  MyLuaMath.h 
     *  MyLuaMath
     *
     *  Created by Jevstein on 2018/10/17 17:36.
     *  Copyright @ 2018year Jevstein. All rights reserved.
     *
     */
    
    #ifdef __cplusplus
    #	define EXTERN_C extern "C"
    #else//!__cplusplus
    #	define EXTERN_C
    #endif//__cplusplus
    
    #ifdef WIN32
    #	ifdef MY_EXPORTS
    #		define MY_REPORT_API EXTERN_C _declspec(dllexport)
    #	else
    #		define MY_REPORT_API EXTERN_C _declspec(dllimport)
    #	endif
    #	define CALLMODE __cdecl //__stdcall
    #else//!WIN32
    #	define MY_REPORT_API EXTERN_C
    #	define CALLMODE
    #endif//WIN32
    
    /************************************************************************/
    /* 函数声明                                                             */
    /************************************************************************/
    int add_func(lua_State* L);
    int sub_func(lua_State* L);
    int mul_func(lua_State* L);
    int div_func(lua_State* L);
    

    C++实现文件:

    /*
     *  MyLuaMath.cpp 
     *  MyLuaMath
     *
     *  Created by Jevstein on 2018/10/17 17:45.
     *  Copyright @ 2018year Jevstein. All rights reserved.
     *
     */
    
    #include <iostream>
    extern "C"
    {
    	#include <lua.h>
    	#include <lauxlib.h>
    	#include <lualib.h>
    }
    #include "MyLuaMath.h"
    
    #define MY_EXPORTS
    
    /************************************************************************/
    /* 1.函数实现                                                           */
    /************************************************************************/
    int add_func(lua_State* L)
    {
    	//if (!lua_isnumber(state, 1))
    	//	printf("type invalid!");
    
    	int a = lua_tonumber(L, 1);
    	int b = lua_tonumber(L, 2);
    	int ret = a + b;
    
    	lua_pushnumber(L, ret);
    	return 1;//1个返回值
    }
    
    int sub_func(lua_State* L)
    {
    	int a = lua_tonumber(L, 1);
    	int b = lua_tonumber(L, 2);
    	int ret = a - b;
    
    	lua_pushnumber(L, ret);
    	return 1;
    }
    
    int mul_func(lua_State* L)
    {
    	int a = lua_tonumber(L, 1);
    	int b = lua_tonumber(L, 2);
    	int ret = a * b;
    
    	lua_pushnumber(L, ret);
    	return 1;
    }
    
    int div_func(lua_State* L)
    {
    	int a = lua_tonumber(L, 1);
    	int b = lua_tonumber(L, 2);
    	int ret = (b == 0) ? 0 : a / b;
    
    	lua_pushnumber(L, ret);
    	return 1;
    }
    
    /************************************************************************/
    /* 2.函数数组                                                           */
    /************************************************************************/
    static const struct luaL_Reg funcs__[] =
    {
    	{ "add", add_func },
    	{ "sub", sub_func },
    	{ "mul", mul_func },
    	{ "div", div_func },
    	{ NULL, NULL }
    };
    
    /************************************************************************/
    /* 3.导出接口                                                           */
    /*   [注]函数名luaopen_libmyluamath中的'libmyluamath'必须为库函数名,如:*/
    /*       libmyluamath.so                                                */
    /************************************************************************/
    MY_REPORT_API int CALLMODE luaopen_libmyluamath(lua_State* L)
    {
    	//lua5.1之前版本使用如下:
    	//luaL_openlib(L, "MyMath", funcs__, 0); //或luaL_register(L, "mymath", funcs__);
    
    	//lua5.2以上版本使用如下:
    	lua_getglobal(L, "MyMath");
    	if (lua_isnil(L, -1))
    	{
    		lua_pop(L, 1);
    		lua_newtable(L);
    	}
    	luaL_setfuncs(L, funcs__, 0);
    	lua_setglobal(L, "MyMath");
    
    	return 0;
    }
    

    然后创建lua脚本,测试C++的功能。文件路径:demo2/demo.lua,内容如下:

    
    package.cpath = package.cpath .. ";./lcpp/?.so"
    
    require("libmyluamath")
    
    local a = 200
    local b = 100
    
    local ret = MyMath.add(a, b)
    print("a + b = " ..a .. " + " .. b .. " = "..ret)
    
    local ret = MyMath.sub(a, b)
    print("a - b = " ..a .. " - " .. b .. " = "..ret)
    
    local ret = MyMath.mul(a, b)
    print("a * b = " ..a .. " * " .. b .. " = "..ret)
    
    local ret = MyMath.div(a, b)
    print("a / b = " ..a .. " / " .. b .. " = "..ret)
    

    linux下用g++编译C++动态库:
    $ g++ -fPIC -shared -o libmyluamath.so *.cpp -llua -ldl
    再用执行脚本:
    $ lua demo.lua

    结果如下:
    在这里插入图片描述

    展开全文
  • C++与lua交互

    2013-12-10 17:40:00
    项目开发的脚本层用的是Lua,...一、C++与Lua数据交互 数据交互主要是通过C API来实现 首先,要加入Lua的头文件 extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib" } 也可以用#incl...

    项目开发的脚本层用的是Lua,引擎用的是C++。但是经理不给开放引擎层的代码。刚好最近项目空闲,安排了学习C++跟Lua的通信。

    一、C++与Lua数据交互

    数据交互主要是通过C API来实现

    首先,要加入Lua的头文件

    extern "C" {

    #include "lua.h"

    #include "lualib.h"

    #include "lauxlib"

    }

    也可以用#include "lua.hpp"代替

    要使用的lua文件为:test.lua,其中有个变量a = 1

     

    1.创建一个Lua虚拟机;

    lua_State *L;

    L=lua_open();

    链接lua库

    luaL_openlibs(L);

    早期版本可能得一个个加载。

    2.导入lua文件

    luaL_dofile(L,"test.lua");

    3.获取想要的lua变量:a

    lua_getglobal(L,"a");

    int b = (int)lua_tonumber(L,-1);

    cout<<b<<endl;

    这样就获取了test.lua中的变量a.

     

    C++与Lua的之间函数的相互调用

    1.C++调Lua函数

    C与lua的所有交互都是通过一个栈来完成的。我对前面提到的虚拟机L的理解是,它就是一个栈(可能理解的不对)。然后通过对这个栈的操作来实现数据的交互。

     

    调用函数跟访问变量其实差不多,前面都是做一样的事,只是调用函数时获取的变量是函数名。然后将需要的参数逐一入栈,最好通过lua_call来调用函数。具体实现如下。

    ********test.lua*************

    function add(x,y)

    return x+y

    end

    ******************************

    int main(int argc,char *argv[])

    {

    int ret;

    int x = 1;

    int y = 2;

    lua_State *L = lua_open();

    luaL_openlibs(L);

    luaL_dofile(L);

    lua_getglobal(L,"add");    //将函数入栈

    lua_pushnumber(L,x);  //变量x入栈

    lua_pushnumber(L,y);   //变量y入栈

    lua_call(L,2,1)      //2表示参数个数,1表示函数返回值的个数。因为lua可以返回多个值。 我的理解是将x,y出栈,计算函数值,并将函数值入栈。这时,函数值就在栈顶。

    ret = lua_tonumber(L,-1)    //获取栈顶元素,并出栈。-1表示对栈顶的偏移量为1。负数时对栈顶的偏移量,正数是对栈底的偏移量。如果返回的是字符串就用lua_tostring。

    lua_pop(L,1);   //将函数出栈

    lua_close(L);

    return 0;

    }

    2.Lua调C++函数

    lua要调用C的函数需要将C函数注册到lua中。

     int add(lua_State *L)

    {

    double sum = 0;

    sum = lua_tonumber(L,-1) + lua_tonumber(L,-2);    //取栈顶两元素,并相加

    lua_pushnumber(L,sum);            //将结果返回给lua

    return 0;

    }

     

     int main(int argc,char *argv[])

    {

    lua_State *L = lua_open();

    luaL_openlibs(L);

    lua_register(L,"_add",add);               //向lua注册C函数,第二个参数是lua中的函数名,第三个参数是C的函数名。

    luaL_dofile(L,"luaandc.lua");             //执行lua文件

    return 0;

    }

    转载于:https://www.cnblogs.com/zhenzi/p/3467903.html

    展开全文
  • c++ lua交互

    2015-03-15 11:47:56
    lua语言是嵌入式语言,c/c++lua是可以相互交互的 第一种情况:c/c++语言具有控制权,Lua是一个库,这种形式的c/c++代码称为应用程序代码 第二种情况:lua具有控制权,c语言是一个库,这个时候c代码就是库代码 应用...

    最近公司需要c++中嵌入lua,抽空学习了下

    学习文档:http://www.jb51.net/article/55843.htm 


    lua语言是嵌入式语言,c/c++和lua是可以相互交互的

    第一种情况:c/c++语言具有控制权,Lua是一个库,这种形式的c/c++代码称为应用程序代码

    第二种情况:lua具有控制权,c语言是一个库,这个时候c代码就是库代码

    应用程序代码和库代码都使用同样的API来与Lua通信,这些API被称为CAPI

    对几个头文件进行解释:

    lua.h定义了Lua提供的基础函数,包括创建Lua环境,调用Lua函数,读写Lua环境中的全局变量以及注册lua调用的新函数等等 

    lauxlib.h定义辅助库提供的辅助函数,他的所有定义都以luaL_开头,辅助库是一个使用lua.h中API编写出的一个较高抽象层,lua的所有标准库编写都用到了辅助库,辅助库主要用来解决实际问题,辅助库并没有直接访问Lua的内部,他都是使用官方的基础API来完成所有工作的

    头文件lualib.h定义了打开标准库的函数,lua库中没有定义任何全局变量,他的所有状态都保存在动态结构lua_State中,所有的CAPI都要求传入一个指向该结构的指针luaL_newstate:用于创建一个新环境或状态,当lua_newstate创建一个新的环境时,新的环境中并没有包含预定义的函数(eg.print)

    为了使lua保持灵活,小巧,所有标准库都被组织到不同的包中,当我们需要使用哪个标准库时,既可以使用lualib.h中定义的函数来打开对应的标准库,而辅助函数luaL_openlibs则可以打开所有的标准库


    栈:

    lua和c/c++语言通信的主要方法是一个虚拟栈,几乎所有API调用都会操作这个栈上的值,所有的数据交换,无论是lua到c/c++或是c/c++到lua都通过这个栈来完成,栈可以解决lua和c/c++语言之间存在的两大差异:

    第一种:lua使用垃圾收集, 而c/c++要求显示的释放内存

    第二种:lua使用动态类型,而c语言使用静态类型

    为了屏蔽两者之间的差异,让彼此之间交互变得通常,便出现了虚拟栈, 栈中的每个元素都能保存任何类型的lua值

    当c/c++代码需要获取lua中的一个值时,只需要调用lua API函数,lua就会将指定的值压入栈中

    当c/c++代码将值传递给lua中, 需要先将这个值压入栈, 然后调用lua API,lua就会获得该值并将其从栈中弹出

    为了将c/c++类型值压入栈中,或者从栈中获取不同类型的值,就需要为每种类型定义一个特定的函数

    lua严格按照LIFO(先进后出)规范来操作这个栈, 但调用lua时,lua只会改变栈的顶部

    c/c++代码有更大的自由度, 他可以检索栈中间的元素,甚至在栈中的任意位置插入或删除元素

    压入栈

    对于每种可以呈现在lua中的c类型,API都有一个对应的压入函数:

    void lua_pushnil(lua_State* L);

    void lua_pushboolean(lua_State *L, int bool);

    void lua_push_number(lua_State *L, lua_Number n);

    void lua_pushinteger(lua_State *L, lua_Integer n);

    const char* lua_pushlstring(lua_State *L, const char *s, size_t l);

    const char* lua_pushstring(lua_State *L, const char *s);

    等等....

    由于这个栈并不是无限大,当向栈中压入一个元素时,应该确保栈中具有足够的空间, 当lua启动时,lua调用c语言时,栈中至少有20个空闲的槽,这些空间一般情况下是足够的,但是会有特殊情况,如果调用一个具有很多参数的函数,就需要调用lua_checkstack来检查栈中会否有足够的空间


    展开全文
  • 进行C++与LUA交互编程的LUA库,版本为5.1.5,32位,包含动态链接和静态链接两种方式
  • c++与lua交互

    千次阅读 2013-06-28 08:42:52
    1 配置工作环境 a 下载LUA安装包 b 然后,解压用于WIN32下的安装包。放在一个盘的目录下如:C:/... 并在LIB库中加入lua+lib.lib ,并将C:/LUA50下的Lua+lib.dll ,Lua+lib.lib拷贝到程序当前所在目录 vc下使用lua

    1、c++中执行和加载lua脚本

    c++中直接执行lua文件,加载lua代码到虚拟机
    main.cpp

    #include <stdio.h>
    
    extern "C" {
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
    }
    /* LUA接口声明*/
    lua_State* L;
    int main ( int argc, char *argv[] )
    {
    	/* 初始化 Lua */
    	L = lua_open();
    	/*载入LUA库 */
    	lua_baselibopen(L);
    	/* 运行LUA脚本 */
    	lua_dofile(L, "test.lua");
    	/* 清除 Lua */
    	lua_close(L);
    	return 0;
    }

    测试脚本test1.lua:

    -- simple test
    print "Hello, World!"


    2、c++与lua相互函数调用 

    (1)c调用lua函数

     lua_call  和 lua_pcall 是提供在c/c++调用lua函数的方法,要求 栈上的顺序是 functor + 参数1 + 参数2 +... 的排列顺序。
    函数声明:
    LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc)
    第一个参数虚拟机指针,第二个参数指定有多少个参数,第三个指定有几个返回值,第四个当发生错误的时候用函数(所在的交互栈的位置,如果是1,表示错误处理函数在栈的1号位置上,就是传入的那个错误处理函数)。
    如果指定有n个参数,则要先把函数入栈,然后再把n个参数压入栈,调用lua_pcall,注意,lua_pcall如果要调用函数,函数必须在栈底。
    如果有指定返回值,在压入结果前,lua_pcall会删除栈中函数及其参数。故lua_pcall后调用lua_pop恢复栈时,只需弹出函数返回值结果数即可。
    lua的虚拟栈是有限的,如果不够用会先破坏先前的数据。

    LUA_API int (lua_call) (lua_State *L, int nargs, int nresults)
    类似lua_pcall,只是没有错误处理函数

    (1-1)调用lua_call

    测试脚本test2.lua:

    ----fun.lua--------
    function add ( x, y )
    return x + y
    end

    调用lua_dofile()将执行脚本,则该脚本代码会被加载到虚拟机中。
     

    LUA的函数可以接收多个参数,并可以返回多种类型的结果,这里使用了堆栈。

    先把函数和参数压栈调用函数lua_call(),调用这个函数之后,返回的结果将存在于堆栈中。

    步骤:
    1.用lua_getglobal()把add函数放入堆栈
    2.用lua_pushnumber()把第一个参数压入堆栈
    3.用lua_pushnumber()把第二个参数压入堆栈
    4.用lua_call()调用函数。
    5,现在用lua_tonumber从堆栈头取出结果
    6,最后用lua_pop从堆栈中移除结果值。


    代码:luaadd.cpp

    #include <stdio.h>
    extern "C" {
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
    }
    //lua虚拟机对象
    lua_State* L;
    int luaadd ( int x, int y )
    {
    	int sum;
    	//压入函数名到栈顶(lua函数)
    	lua_getglobal(L, "add");
    	//压入第一个参数
    	lua_pushnumber(L, x);
    	//压入第二个参数
    	lua_pushnumber(L, y);
    	//执行栈底函数,传入两个参数,返回一个结果
    	lua_call(L, 2, 1);//或者lua_pcall(L,2,1,0);
    	//获取栈顶结果
    	sum = (int)lua_tonumber(L, -1);
    	lua_pop(L, 1);//清除结果
    	return sum;
    }
    
    int main ( int argc, char *argv[] )
    {
    	int sum;
    	//初始化虚拟机对象
    	L = lua_open();
    	//加载lua类库
    	lua_baselibopen(L);
    	//加载lua脚本
    	lua_dofile(L, "add.lua");
    	//执行lua中的add函数,返回结果
    	sum = luaadd( 10, 15 );
    	//打印结果
    	printf( "The sum is %d\n", sum );
    	//清除lua虚拟机
    	lua_close(L);
    	return 0;
    }

    (1-2)调用lua_pcall

    使用lua_pcall 调用lua函数,并在出错时处理错误。

    错误处理函数在lua虚拟机中,名为__G__TRACKBACK__

    lua_getglobal(L, "__G__TRACKBACK__");//通过函数名,压入错误处理函数  
    
    if (lua_type(L, -1) != LUA_TFUNCTION)   //尼马,居然找不到,那肯定是拼写错误!  
    {  
    	printf("[LUA ERROR] can't find function <__G__TRACKBACK__>err");  
    	lua_settop(L, top);  
    	return;  
    }  
    
    int errfunc = lua_gettop(m_state);                   //刚压入的函数,肯定是栈顶哦,那gettop就是他的索引  
    
    lua_getglobal(L, "main");                     //查找要执行的函数  
    if (lua_type(L, -1) != LUA_TFUNCTION)  
    {  
    	printf("[LUA ERROR] can't find function <main>err:%s", lua_tostring(m_state, -1));  
    	lua_settop(m_state, top);  
    	return;  
    }  
    if (lua_pcall(L, 0, 0, errfunc) != 0)  //执行函数main,参数0,返回值0,errfunc是错误处理函数  
    {  
    	lua_settop(L, top);  
    	return;  
    }  
    lua_settop(L, top);  


    1)错误处理函数

    下面提供一个错误处理函数,功能是打印栈内的错误信息

    local function tostringex(v, len)  
     if len == nil then len = 0 end  
     local pre = string.rep('\t', len)  
     local ret = ""  
     if type(v) == "table" then  
      if len > 5 then return "\t{ ... }" end  
      local t = ""  
      for k, v1 in pairs(v) do  
       t = t .. "\n\t" .. pre .. tostring(k) .. ":"  
       t = t .. tostringex(v1, len + 1)  
      end  
      
      if t == "" then  
       ret = ret .. pre .. "{ }\t(" .. tostring(v) .. ")"  
      else  
       if len > 0 then  
        ret = ret .. "\t(" .. tostring(v) .. ")\n"  
       end  
      
       ret = ret .. pre .. "{" .. t .. "\n" .. pre .. "}"  
      end  
     else  
      ret = ret .. pre .. tostring(v) .. "\t(" .. type(v) .. ")"  
     end  
      
     return ret  
    end  
      
    local function tracebackex(msg)  
     local ret = ""  
     local level = 2  
     ret = ret .. "stack traceback:\n"  
     while true do  
      --get stack info  
      local info = debug.getinfo(level, "Sln")  
      if not info then break end  
      if info.what == "C" then                -- C function  
       ret = ret .. tostring(level) .. "\tC function\n"  
      else           -- Lua function  
       ret = ret .. string.format("\t[%s]:%d in function `%s`\n", info.short_src, info.currentline, info.name or "")  
      end  
      --get local vars  
      local i = 1  
      while true do  
       local name, value = debug.getlocal(level, i)  
      
       if not name then break end  
       ret = ret .. "\t\t" .. name .. " =\t" .. tostringex(value, 3) .. "\n"  
       i = i + 1  
      end  
      level = level + 1  
     end  
     return ret  
    end  
      
    local function tracebackAndVarieble(msg)  
        print(tracebackex())  
    end  
      
    __G__TRACKBACK__ = tracebackAndVarieble  

    测试例子

    function main()  
     printf("function main start")  
     local a = 1  
     p[2] = 2   --这里写了一个错误用来触发错误处理  
     printf("function main finished")  
    end  

    输出结果如:

    [LUA-print] stack traceback:  
     [[string "script/DebugTool.lua"]]:57 in function ``  
      msg =    ...\script/main.lua:8: attempt to index global 'p' (a nil value) (string)  
      (*temporary) =    function: 0512A6D8 (function)  
     [...\script/main.lua]:8 in function ``  
      a =    1 (number)  
      (*temporary) =    nil (nil)  
      (*temporary) =    nil (nil)  
      (*temporary) =    attempt to index global 'p' (a nil value) (string)  


    (2) lua中调用c++函数

    需要在C/C++中的函数能被Lua调用,函数定义类型: 
    typedef int (*lua_CFunction) (lua_State *L);

    函数需要满足条件:

    1)函数以Lua虚拟机对象作为参数,并且返回值为int类型。

    2)函数可以从栈中取得任意多个参数。

    3)返回的整数值代表入栈的值的数目。


    下面的C++的average函数例子中,可以清楚地看到Lua中调用C/C++函数是如何实现的。 
    1) lua_gettop()返回栈顶的下标索引,由于Lua中栈的下标从1开始,这个返回值实际上也就是函数参数的个数。 
    2) For循环计算各个参数总和。 
    3) Average的参数是通过调用lua_pushnumber()入栈的。 
    4) 然后参数之和被入栈。 
    5) 最后,函数返回值为2,表明有两个返回值,并且已经入栈。 
    6)注册函数到虚拟机(类库加载之后)。 
     

    #include <stdio.h>
    extern "C" {
           #include "lua.h"
           #include "lualib.h"
           #include "lauxlib.h"
    }
    //虚拟机对象声明
    lua_State* L;
    static int average(lua_State *L)
    {
           int n = lua_gettop(L);//获取参数个数
           double sum = 0;
           int i;
           //获取每个参数(从栈底第一个开始是第一个参数)
           for (i = 1; i <= n; i++)
           {
               //所有的参数的和
               sum += lua_tonumber(L, i);
           }
          //压入平均值 
           lua_pushnumber(L, sum / n);
           //压入和
           lua_pushnumber(L, sum);
          //返回结果个数(也就是压入的结果数量)
           return 2;
    }
    int main ( int argc, char *argv[] )
    {
           //初始化虚拟机
           L = lua_open();
           //加载虚拟机类库 
           lua_baselibopen(L);
          //注册函数(c++函数)
           lua_register(L, "average", average);
           //运行脚本
           lua_dofile(L, "avg.lua");
           //清除虚拟机
           lua_close(L);
           return 0;
    }


     Lua脚本,调用C/C++函数,并打印其返回值,保存为avg.lua

    函数average是在c/c++中注册的函数,调用时,函数参数会都压到堆栈中,调用完毕后,堆栈上的参数会被清除并压入结果,返回结果后,堆栈上的结果会被清除。在lua环境中,交互堆栈调用函数前后是空的。

    avg, sum = average(10, 20, 30, 40, 50)
    print("The average is ", avg)
    print("The sum is ", sum)

    编译:
    g++ luatest.cpp -llua -llualib -o luatest


    运行结果:

    The average is 5

    The sum is 25


    3、lua交互栈的使用

     lua的栈是在创建lua_State的时候创建的
    TValue stack[max_stack_len]  // 在 lstate.c 的stack_init函数 。
    存入栈的数据类型包括数值, 字符串, 指针, talbe, 闭包等
    栈如下图所示

    执行的代码如:

    <span style="font-size:12px;">lua_pushcclosure(L, func, 0) // 创建并压入一个闭包   
    lua_createtable(L, 0, 0)        // 新建并压入一个表   
    lua_pushnumber(L, 343)      // 压入一个数字   
    lua_pushstring(L, “mystr”)   // 压入一个字符串  </span>

    (1)栈的序号和数量

    堆栈的序号可以从栈顶和栈底计数,从栈底计数,则栈底是1,向栈顶方向递增。

    从栈顶计数,则栈顶是-1,向栈底方向递减。一般都用从栈顶计数的方式。堆栈的默认大小是20,可以用lua_checkstack修改.

    用lua_gettop则可以获得栈里的元素数目。并不是说在栈顶有一个整形元素。而是计算了一下栈顶元素在栈里的正index,相当于元素数目。 

    (2)栈中的值

    这里要说明的是, 你压入的类型有数值, 字符串, 表和闭包[在c中看来是不同类型的值], 但是最后都是统一用TValue这种数据结构来保存的:), 下面用图简单的说明一下这种数据结构:


    TValue结构对应于lua中的所有数据类型, 是一个{值, 类型} 结构, 这就lua中动态类型的实现, 它把值和类型绑在一起, 用tt记录value的类型, value是一个联合结构, 由Value定义, 可以看到这个联合有四个域, 先说明简单的

            p -- 可以存一个指针, 实际上是lua中的light userdata结构

            n -- 所有的数值存在这里, 不过是int , 还是float

            b -- Boolean值存在这里, 注意, lua_pushinteger不是存在这里, 而是存在n中, b只存布尔

            gc -- 其他诸如table, thread, closure, string需要内存管理垃圾回收的类型都存在这里

            gc是一个指针, 它可以指向的类型由联合体GCObject定义, 从图中可以看出, 有string, userdata, closure, table, proto, upvalue, thread

        从下面的图可以的得出如下结论:

            1. lua中, number, boolean, nil, light userdata四种类型的值是直接存在栈上元素里的, 和垃圾回收无关.

            2. lua中, string, table, closure, userdata, thread存在栈上元素里的只是指针, 他们都会在生命周期结束后被垃圾回收.


    lua value 和 c value的对应关系

                 c          lua
             nil           无    {value=0, tt = t_nil}
          boolean       int  非0, 0    {value=非0/0, tt = t_boolean}
          number       int/float等   1.5    {value=1.5, tt = t_number}
       lightuserdata    void*, int*, 各种*  point    {value=point, tt = t_lightuserdata}
          string          char  str[]    {value=gco, tt = t_string}   gco=TString obj
          table            无    {value=gco, tt = t_table}  gco=Table obj
          userdata            无    {value=gco, tt = t_udata} gco=Udata obj
          closure            无    {value=gco, tt = t_function} gco=Closure obj

     

    可以看出来, lua中提供的一些类型和c中是对应的, 也提供一些c中没有的类型. 其中有一些药特别的说明一下:

            nil值, c中没有对应, 但是可以通过lua_pushnil向lua中压入一个nil值

            注意: lua_push*族函数都有"创建一个类型的值并压入"的语义, 因为lua中所有的变量都是lua中创建并保存的, 对于那些和c中有对应关系的lua类型, lua会通过api传来的附加参数, 创建出对应类型的lua变量放在栈顶, 对于c中没有对应类型的lua类型, lua直接创建出对应变量放在栈顶.

           例如:    lua_pushstring(L, “string”) lua根据"string"创建一个 TString obj, 绑定到新分配的栈顶元素上

                      lua_pushcclosure(L,func, 0) lua根据func创建一个 Closure obj, 绑定到新分配的栈顶元素上

                      lua_pushnumber(L,5) lua直接修改新分配的栈顶元素, 将5赋值到对应的域

                      lua_createtable(L,0, 0)lua创建一个Tabke obj, 绑定到新分配的栈顶元素上

    总之, 这是一个 c value –> lua value的流向, 不管是想把一个简单的c数据放入lua的世界, 还是创建一个table, 都会导致

                      1. 栈顶新分配元素    2. 绑定或赋值

                    还是为了重复一句话, 一个c value入栈就是进入了lua的世界, lua会生成一个对应的结构并管理起来, 从此就不再依赖这个c value

            lua value –> c value时, 是通过 lua_to* 族api实现, 很简单, 取出对应的c中的域的值就行了, 只能转化那些c中有对应值的lua value, 比如table就不能to c value, 所以api中夜没有提供 lua_totable这样的接口

    (3)c访问lua堆栈

    (3-1)原子类型的读取

    Lua 调用C函数用的堆栈是临时的,调用结束之后就被销毁了。 
    如何从堆栈中获取从Lua脚本中的参数 
    如果知道Lua脚本中某个全局变量的名字,可以用void lua_getglobal (lua_State *L, const char *name) 。这个函数会将name所指Lua变量(或函数)的值放在栈顶. 
    如果是在C 函数中要获取Lua调用函数使用的参数: 
    首先用lua_gettop检查参数数量 
    用lua_is...类函数检测参数的类型,做好错误处理 
    用lua_to...类函数将参数转换为number或者string.(对Lua来说,只有这两种简单类型) 
    lua_tonumber返回的是double 
    lua_tostring返回的是char* 
    用lua_remove从栈中删除掉元素 
    继续获取下一个元素. 因为每次都调用lua_remove,所以每次调用lua_tonumber,使用的index都将固定是-1,即栈顶。 
    如果lua_istable成立,那么说明栈顶是一个table.注意table是不能取出来的,只能把table里的元素一个个取出来。 

    (3-2)表的读取

    1)遍历方式1(表中的key是从1开始的递增的数):

    当table在栈顶时,

    将一个key放到栈顶,这个key为1。如果你的key是字符串,那就用lua_pushstring。

    lua_pushnumber(L, 1);

    table一开始是在栈顶,即-1处的,但上面的语句压入了一个值,栈顶变-2了。

    lua_gettable的作用就是以栈顶的值作为key来访问-2位置上的table。

    lua_gettable(L, -2);

    这时table中的第1个元素的值就放到栈顶了。

    上面说的是访问table中的一个元素的方法,那要怎么样遍历table中的所有元素呢?如果table是一个以连续的整形作为key的table, 可以用下面方法:

    int size = lua_objlen(L,-1);//相关于#table  
    for(int i = 1; i <= size; i++)  
    {  
    lua_pushnumber(L, i);  
    lua_gettable(L, -2);  
    //这时table[i]的值在栈顶了  
    lua_pop(L, 1);//把栈顶的值移出栈,保证栈顶是table以便遍历。  
    };  

    2)遍历方式2(表中的key是任意值):

    当表在位置t时,调用函数int lua_next (lua_State *L, int index); 会弹出键key,然后压入键和值到-2和-1的位置。

    如果表内没有元素,则不压入任何数到栈。(表在t的位置)

    /* table is in the stack at index 't' */
    lua_pushnil(L);  /* first key */
    while (lua_next(L, t) != 0) {
     /* 'key' is at index -2 and 'value' at index -1 */
     printf("%s - %s\n",
       lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
     lua_pop(L, 1);  /* removes 'value'; keeps 'key' for next iteration */
    }
    lua_next遍历表的堆栈示意图:

    当表在栈顶时:

    lua_pushnill(L);  
    while(lua_next(L, -2))  
    {  
    //这时值在-1(栈顶)处,key在-2处,表在-3处  
    lua_pop(L, 1);//把栈顶的值移出栈,让key成为栈顶以便继续遍历  
    }  

    lua_next操作:

    先判断表位置的上一个位置的key的值(这个值放在栈顶,如果是nil,则表示取表的第一个值到栈顶,如此类推到表元素结束。


    (4)从C通过堆栈传递数据给Lua脚本

    在lua脚本中调用c函数,获取返回的值

    (4-1)传递原子类型

      用lua_push...类函数压入数据到堆栈中,并用return n;来告诉Lua返回了几个返回值(入栈的数量)。 Lua是天生支持多个返回值的,如 x,y = Test()。 Lua会根据n从栈里取相应的数据。

    (4-2)传递table类型

    在c环境,压入一个table,该table中还有子table,并返回,操作例子如下: 

    lua_newtable(L);  //创建一个表格,放在栈顶 
    lua_pushstring(L, "mydata");  //压入key 
    lua_pushnumber(L,66);  //压入value 
    lua_settable(L,-3);  //弹出key,value,并设置到table里面去 
    lua_pushstring(L, "subdata");  //压入key 
    lua_newtable(L);  //压入value(一个table) 
    lua_pushstring(L, "mydata");  //压入subtable的key 
    lua_pushnumber(L,53);  //value 
    lua_settable(L,-3);  //弹出key,value,并设置到subtable 
    lua_settable(L,-3);  //这时候父table的位置还是-3,弹出key,value(subtable),并设置到table里去 
    lua_pushstring(L, "mydata2");  //同上 
    lua_pushnumber(L,77); 
    lua_settable(L,-3); 
    return 1;//堆栈里现在就一个table



     
    展开全文
  • C++与LUA交互

    2013-03-29 14:49:30
    脚本化编程的最大好处就是简单灵活,另外就是热更新,这在网游中广泛被采用,在网游中,通常采用引擎(c/C++)+脚本(lua/python)的架构,那种SDK性质的代码放在引擎中,这些代码在游戏上线后通常很稳定很少被修改...
  • C++与Lua交互原理

    千次阅读 2018-07-11 14:26:02
    C++与Lua交互原理首先,不同语言交互,我们一般把这种编程方式称为混合编程。开发中为什么要多语言混合使用,只用c++不行吗?答案是因为脚本语言语法糖多使用方便、沙盒式安全机制使系统更稳定、简单易学降低开发...
  • 解决C++ 工程调取带有socket功能的lua脚本无法调取执行问题,附件为lua socket 源代码,可自行生成lua socket 环境,支持lua5.3 ,详细操作步骤请参考:https://blog.csdn.net/wantedww/article/details/112094145
  • 一、官网下载lua src 官网地址,链接: http://www.lua.org/versions.html#5.3.选择需要的lua版本,下载 二、使用步骤 1.引入库 代码如下(示例): import numpy as np import pandas as pd import matplotlib....
  • C/C++与Lua交互

    2018-11-06 21:28:02
    1.什么是Lua Lua [1] 是一个小巧的脚本语言。是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de ...
  • cocos2dx中C++与lua交互

    2018-10-29 11:57:58
    最近在写热更新的模块,目的是C++调用CRUL multi接口实现多线程... lua与C++交互是使用lua的registry表,C/C++代码可以自由使用,但Lua代码不能访问他.为每一个要注册到lua的数据,在registry创建一个元表.以类型名...
  • 一、搭建C++调用Lua环境一、环境准备从Lua5.1.4开始官方给出的文件只有源代码和makefile文件了,官网给出的bulid方式也是在类linux平台,如果只是想找个库使用下可以到这里来下载:joedf.ahkscript.org/Lua,如果...
  • 那也是不合理的,因为系统api的接口、计算密集性模块的性能要求等是脚本语言不擅长的,这一部份仍然需要c/c++来完成。因此,为了综合各自的优势,就出现了混合编程的需要。那么,在一个程序...
  • c++与lua互相调用(内嵌式) 1.下载lualua固网 2.解压 tar-zxvf 3.将源码导入项目里面,去掉lua.c和luac.c里面的main方法,在使用之前创建一个lua.hpp文件,作为后面的头文件 #ifndef LUA_HPP #define LUA_HPP // lua...
  • C++与Lua交互的C API

    2017-02-14 13:50:18
    1、C API的介绍 Lua是一种嵌入式的语言。即Lua不是一个单独运行的程序,而是一个可以链接到其他程序的库。...由于LuaC++的数据结构和内存机制不一样,所以在交互的时候需要用到C API提供的一个虚拟栈,
  • C++与Lua交互(四)

    2015-01-27 14:45:00
    C++调用Lua数据时,我们主要运用lua_getglobal与lua_push*配合以达到目的。现在我们来试试用Lua调用C++数据。 C++数据类型映射到Lua C++中数据类型有这么几种:1、内建的int、float等;2、指针,如void *、int *...
  • C++与Lua交互(三)

    2014-03-13 11:59:00
    通过上一篇的热身,我们对C++调用lua变量有了一个认识,现在让我们再深入一点,去探索一下如何调用lua的...lua用一个抽象的栈宿主语言交互,栈中的每一条记录都可以保存lua值。无论何时,我们想要从lua请求一个...
  • C++与Lua交互(二)

    2012-10-30 23:04:32
    C++与Lua的之间函数的相互调用 1.C++调Lua函数 C与lua的所有交互都是通过一个栈来完成的。我对前面提到的虚拟机L的理解是,它就是一个栈(可能理解的不对)。然后通过对这个栈的操作来实现数据的交互。   调用...
  • !...makefile ``` .SUFFIXES: .cpp .o .PHONY: clean all CC = g++ ...CFLAGS = -Wall -g ...LIBS = -lpthread -std=c++11 -l /usr...最后编译的时候显示无法找到与lua相关的.h文件,解决方法是什么。。。大神来指导一下
  • C++与Lua交互(五)

    2015-01-27 14:46:00
    要将C++中的对象类型映射到Lua中,就不得不要先了解Lua面向对象的机制。在这里,我们先看一下Lua面向对象的实现基础——metatable,再以此实现C++对象到Lua的映射。 Lua面向对象 不得不先提一下Lua的几种函数写法...
  • Lua 简介 Lua 是一种轻量小巧的脚本语言,也是号称性能最高的脚本语言,它用C语言编写并以源代码形式开放。 某些程序常常需要修改内容,而修改的内容不仅仅是数据,更要修改很多函数的行为。 而修改函数行为...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 456
精华内容 182
关键字:

c++与lua交互

c++ 订阅