zoukankan      html  css  js  c++  java
  • lua:lua与C/C++程序的整合

    https://www.cnblogs.com/dimin/p/7838674.html

    https://blog.csdn.net/nekocode/article/details/7960371

    lua与C/C++交互,主要靠lua API和向lua注册好的函数。如下图

    注:LuaGlue就是让Lua脚本中可调用的C++函数的接口。即那些注册的函数。

    这里起关键作用的要数lua_State的结构,这就得讲一下Lua环境和Lua Stack。

    Lua环境

    Lua环境由所有可操作的数据构成,如编译好的函数、变量以及其他运行时内存。这些数据保存在一个称做lua_State的结构中。所有Lua应用程序都要求至少有一个lua_State,如果需要还可以有多个(如需要为两个不同的系统保存不同的数据时)。

    Lua Stack

    对于我们来说,Lua环境是用来发送和接收数据的地方,它利用栈(Lua Stack)来达到该目的。所有的数据交换,无论是Lua到C/C++语言或C/C++语言到Lua都通过这个栈来完成。Lua栈不同于系统栈,它只能通过Lua的API函数访问。

    注册到Lua中的函数

    所有注册到Lua中的函数都具有相同的原型

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

    这个函数仅有一个参数,即Lua的状态。它返回一个整数,表示其压入栈中的返回值数量。因此函数无须在压入结果前清空栈。在它返回后,Lua会自动删除栈中结果之下的内容。

    在Lua使用这个函数前,必须注册这个函数。

    void lua_pushcfunction (lua_State *L, lua_CFunction f);

    将一个 C 函数压入堆栈。 这个函数接收一个 C 函数指针,并将一个类型为 function 的 Lua 值 压入堆栈。当这个栈顶的值被调用时,将触发对应的 C 函数。

    这种方法需要重新编译Lua的执行程序,才能在Lua程序中使用这个新函数。但用下面的方法会更好,直接将C函数链接到lua。

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Lua调用C函数时,并不依赖于函数名、包的位置或可见性规则,而只依赖于注册时传入的函数地址。当用C函数扩展Lua时,最好将代码设计为一个C模块。因为现在只注册一个函数,但说之后可能会需要更多的函数。辅助库为这项工作提供了一个函数luaL_register,这个函数接收一些C函数及其名称,并将这些函数注册到一个与模块同名的table中。例如,假设创建一个模块,其中包含了这个luaglue函数。首先,必须定义这个模块函数:

    static int luaglue(lua_state *L)
    {
    }

    然后,声明一个数组,其中包含模块中所有函数及名称。这个数组元素的类型为luaL_Reg结构,该结构有两个字段,一个字符串和一个函数指针:

    static const struct luaL_Reg mylib[] = {
    {"dir",l_dir},
    {NULL,NULL}//结尾
    };

    最后,声明一个主函数,其中用到了luaL_register:

    int luaopen_mylib(lua_State *L)
    {
         luaL_register(L,"mylib",mylib);
         return 1;
    }

    其中luaL_register原型为:

    void luaL_register (lua_State *L,const char *libname,const luaL_Reg *l);

    luaL_register根据给定的名称(“mylib”)创建(或复用)一个table,并用数组mylib中的信息填充这个table。在luaL_Register返回时,会将这个table留在栈中。最后,luaopen_mylib函数返回1,表示将这个table返回给Lua。

    ps:打开一个库,当libname为null时,该函数注册所有在luaL_Reg上的函数,不为null时,该函数会创建一个table,根据libname注册不与libname关联的函数。

    当写完c模块后,必须将其链接到解释器。如果Lua解释器支持动态链接的话,那么最简便的方法是使用动态链接机制。在这种情况中,必须将c代码编译成动态链接库,并将这个库放入C路径(LUA_CPATH)中。然后,便可以用require从Lua中加载这个模块:

    require "mylib"

    这名调用会将动态库mylib链接到Lua,并会寻找luaopen_mylib函数,将其注册为一个Lua函数,然后调用它以打开模块。

    如果解释器不支持动态链接,那么就必须用新的模块来重新编译Lua。此外,还需要以某种方式来告诉解释器,它应在打开一个新状态的同时打开这个模块。最简单的做法是,将luaopen_mylib加到luaL_openlibs会打开的标准库列表中,这个列表在文件linit.c中。

    从C++程序员的观点来看,Lua像一个“黑盒子”,为一些服务处理命令和调用。Lua通常作为最上层接口直接和程序使用者和游戏玩家打交道,在核心程序处理之前接受并响应输入。

    如果嫌麻烦,不想手动写这些代码的话,我推荐lua_tinker。也就只有两个文件,lua_tinker.h,lua_tinker.cpp。

    环境配置,首先你需要搭建一个可以用lua的开发环境,这里网上有很多,我就不多说了。然后再将lua_tinker的lua_tinker.h和lua_tinker.cpp添加到你的工程中就可以了。

    lua_tinker::def(L, "cpp_func", cpp_func); //在L栈中注册C++函数
    lua_tinker::dofile(L, "sample1.lua"); //加载lua文件
    int result = lua_tinker::call<int>(L, "lua_func", 3, 4); //调用lua中的function lua_func
    
    lua_tinker::class_add(L,"classA");//在lua中注册类
    lua_tinker::class_con(L,lua_tinker::constructor<classA>);//在lua中注册构造函数
    lua_tinker::class_mem(L,"memName",&classA::memName);

    ps:用lua_tinker::call是要注意,参数不支持智能指针

     

  • 相关阅读:
    LightOJ 1132 Summing up Powers(矩阵快速幂)
    hdu 3804 Query on a tree (树链剖分+线段树)
    LightOJ 1052 String Growth && uva 12045 Fun with Strings (矩阵快速幂)
    uva 12304 2D Geometry 110 in 1! (Geometry)
    LA 3263 That Nice Euler Circuit (2D Geometry)
    2013 SCAUCPC Summary
    poj 3321 Apple Tree (Binary Index Tree)
    uva 11796 Dog Distance (几何+模拟)
    uva 11178 Morley's Theorem (2D Geometry)
    动手动脑
  • 原文地址:https://www.cnblogs.com/losophy/p/9257825.html
Copyright © 2011-2022 走看看