C\C++和Lua是如何进行通信的?

为了实现Lua和其他语言之间的通信,Lua虚拟机为C/C++提供了两个特性:
一,Lua_State状态机

   lua_State主要是管理一个lua虚拟机的执行环境, 一个lua虚拟机可以有多个执行环境。Lua虚拟机通过维护这样一个虚拟栈来实现两种之间的通信,lua_State定义如下:
struct lua_State {
  CommonHeader;
  lu_byte status;
  StkId top;  / first free slot in the stack /
  global_State *l_G;
  CallInfo ci;  / call info for current function */
  const Instruction oldpc;  / last pc traced */
  StkId stack_last;  / last free slot in the stack /
  StkId stack;  / stack base /
  int stacksize;
  unsigned short nny;  / number of non-yieldable calls in stack /
  unsigned short nCcalls;  / number of nested C calls /
  lu_byte hookmask;
  lu_byte allowhook;
  int basehookcount;
  int hookcount;
  lua_Hook hook;
  GCObject openupval;  / list of open upvalues in this stack */
  GCObject *gclist;
  struct lua_longjmp errorJmp;  / current error recover point */
  ptrdiff_t errfunc;  / current error handling function (stack index) /
  CallInfo base_ci;  / CallInfo for first level (C calling Lua) /
};

    1,虚拟栈的管理, 包括管理整个栈和当前函数使用的栈的情况

    2,CallInfo的管理, 包括管理整个CallInfo数组和当前函数的CallInfo

    3,hook相关的, 包括hookmask, hookcount, hook函数等

    4,global_State是全局唯一的,存放多个lua_State之间的一些共享数据

    5,gc的一些管理和当前栈中upvalue的管理

    6,错误处理的支持等等

    C/C++和Lua拥有不同的数据类型,要实现两者之间的数据通信怎么办?Lua虚拟机提供Lua_State这样一种数据结构。任何一种数据从C/C++传入Lua虚拟机中,Lua都会将这类数据转换为一种通用的结构lua_TValue,并且将数据复制一份,将其压入虚拟栈中。lua_TValue定义如下:
struct lua_TValue {
  TValuefields;
};

#define TValuefields  \
    union { struct { Value v__; int tt__; } i; double d__; } u

union Value {
  GCObject gc;    / collectable objects */
  void p;         / light userdata */
  int b;           / booleans /
  lua_CFunction f; / light C functions /
  numfield         / numbers /
};

   Lua有自己的GC,C/C++由自己申请和释放内存,所以两者之间的内存管理是独立的。从C/C++中传递数据到Lua虚拟机会发生数据拷贝,从Lua虚拟机中传递出来是直接从虚拟栈中取值或者地址,所以数据从虚拟栈中pop之后,是否依然是有效引用需要额外注意。

二,C API

Lua脚本实现交互提供了一系列的C API,常用API有:

    luaL_newstate函数用于初始化一个lua_State实例

    luaL_openlibs函数用于打开Lua中的所有标准库,如io库、string库等。

    luaL_loadbuffer编译了buff中的Lua代码,如果没有错误,则返回0,同时将编译后的程序块压入虚拟栈中。

    lua_pcall函数会将程序块从栈中弹出,并在保护模式下运行该程序块。执行成功返回0,否则将错误信息压入栈中。

    lua_tostring函数中的-1,表示栈顶的索引值,栈底的索引值为1,以此类推。该函数将返回栈顶的错误信息,但是不会将其从栈中弹出。

    lua_pop是一个宏,用于从虚拟栈中弹出指定数量的元素,这里的1表示仅弹出栈顶的元素。

    lua_close用于释放状态指针所引用的资源。

入栈操作:

    Lua针对每种C类型,都有一个C API函数与之对应,如:

    void lua_pushnil(lua_State* L);  --nil值

    void lua_pushboolean(lua_State* L, int b); --布尔值

    void lua_pushnumber(lua_State* L, lua_Number n); --浮点数

    void lua_pushinteger(lua_State* L, lua_Integer n);  --整型

    void lua_pushlstring(lua_State L, const char s, size_t len); --指定长度的内存数据

    void lua_pushstring(lua_State L, const char s);  --以零结尾的字符串,其长度可由strlen得出。

出栈操作:

    API使用“索引”来引用栈中的元素,第一个压入栈的为1,第二个为2,依此类推。我们也可以使用负数作为索引值,其中-1表示为栈顶元素,-2为栈顶下面的元素,同样依此类推。

    Lua提供了一组特定的函数用于检查返回元素的类型,如:

    int lua_isboolean (lua_State *L, int index);

    int lua_iscfunction (lua_State *L, int index);

    int lua_isfunction (lua_State *L, int index);

    int lua_isnil (lua_State *L, int index);

    int lua_islightuserdata (lua_State *L, int index);

    int lua_isnumber (lua_State *L, int index);

    int lua_isstring (lua_State *L, int index);

    int lua_istable (lua_State *L, int index);

    int lua_isuserdata (lua_State *L, int index);

    以上函数,成功返回1,否则返回0。需要特别指出的是,对于lua_isnumber而言,不会检查值是否为数字类型,而是检查值是否能转换为数字类型。

文章转载自 开源中国社区 [http://www.oschina.net]

时间: 2024-09-28 04:52:46

C\C++和Lua是如何进行通信的?的相关文章

Lua和C++的通信流程代码实例_Lua

上一章传送门:http://www.jb51.net/article/55088.htm 本章我们来学习一个小Demo,也就是上一章中的场景:C++从Lua中获取一个全局变量的字符串. 1. 引入头文件 我们来看看要在C++中使用Lua,需要些什么东西 复制代码 代码如下: /*    文件名:    HelloLua.h    描 述:    Lua Demo    创建人:    笨木头    创建日期:   2012.12.24 */  #ifndef __HELLO_LUA_H_ #de

Lua和C++的通信流程分解_Lua

网上关于Lua的教程似乎还没有泛滥,最近刚好学习在Cocos2d-x使用Lua,当然了,我是写教程狂,我会分享我的学习心得的~ (旁白:我噗~!每次你写东西我就要吐槽,你不累么= =)   这是第一课,先来让Lua和C++认识一下,顺便让它们逛街吃饭牵小手什么的- (旁白:...吹,继续吹) 1. Lua的堆栈和全局表 我们来简单解释一下Lua的堆栈和全局表,堆栈大家应该会比较熟悉,它主要是用来让C++和Lua通信的,是的,它们并不认识对方,只能通过堆栈来沟通,就像写信一样. (旁白:它们不会用

Lua 服务器Socket通信实例(转)

  local socket = require"socket" local host = "127.0.0.1"local port = "843"local sever = assert(socket.bind(host, port)) --绑定sever:settimeout(nil)   --不设置阻塞local tab = {}table.insert(tab, sever) while 1 do  local s  s,_,_ = s

Java调用Lua(转)

Java 调用 Lua app发版成本高,覆盖速度慢,覆盖率页低.一些策略上的东西如果能够从服务端控制会方便一些.所以考虑使用Lua这种嵌入式语言作为策略实现,Java则是宿主语言. 总体上看是一个模板方法模式.Lua提供模板方法,其中需要的一些具体实现则有宿主语言Java提供. 1. Luaj:Java与Lua的桥梁 能够作为Java与Lua进行通信的桥梁工具还有别的一些.但是Luaj 是用纯Java实现,客户端容易加载.且目前还一直有更新和维护,相对感觉靠谱. 需要注意的是: 新版的LuaJ

《Lua游戏AI开发指南》一导读

前 言 Lua游戏AI开发指南 游戏人工智能(Artificial Intelligence,AI)是决策制定和动画回放的结合体.经典AI或学术AI仅仅关注于找到正确的决策,游戏AI则负责在游戏运行期间做出大量的决策.将游戏AI与动画分开处理是常见的错误.本书通过把动画和运动系统直接集成到AI系统中来杜绝这一问题.决策制定和决策执行之间微妙的差异会改变AI程序员不得不关注的诸多方面. 游戏AI的另一个大问题是,不同类型的游戏对AI有不同的需求和实现策略.为了避免毫无重点的平铺直述,本书将只关注一

《Lua游戏开发实践指南》一1.3为什么使用Lua

1.3为什么使用Lua 对于游戏开发而言,Lua是较好的选择,其设计的核心目标是可扩展性,因此在最初设计时就考虑到要能够集成在大型应用中.因为有了这样的设计目标,所以非常容易在应用程序中加入Lua脚本.Lua的易集成的特性还使得Lua可以很方便地与父程序通信.游戏程序员都希望脚本语言能够简单地实现游戏设计,在这方面,Lua也能够胜任.Lua免费.小巧.快速且易移植.所有的游戏开发者和游戏公司都喜欢"免费"的工具.通常讲,一分钱一分货,但是对于Lua来说,它完全超出你的预期.Lua采用了

Lua编程示例(八):生产者-消费者问题_Lua

这个问题是比较经典的啦,基本所有语言的多线程都会涉及到,但是没想到Lua的这个这么复杂 抓狂   看了好长时间才算看明白,先上个逻辑图:    开始时调用消费者,当消费者需要值时,再调用生产者生产值,生产者生产值后停止,直到消费者再次请求.设计为消费者驱动的设计.    图画的不太好,可以先将Filter遮住,它是过滤器对两个程序之间传递的信息进行处理.去掉Filter逻辑就更清晰些了,就是两个"线程"(其实是两个协同程序)互相调用.resume回到yield处开始,支持嵌套,返回到栈

Lua教程(三):C语言、C++中调用Lua的Table示例_Lua

从写上一篇Lua的文章到现在,已经过去半月有余了,是时候让自己的Lua状态refresh一下了.本教程将介绍Lua的栈及基本栈操作,同时还有如何在C/C++代码里面读取Lua的Table. 理解Lua栈 Lua通过一个"虚拟栈"与C/C++程序进行数据交互,所有的Lua C API都是通过操作这个栈来完成相应的数据通信. Lua的这个"虚拟栈"解决了C/C++程序与Lua程序通信的两大问题: 1.Lua使用垃圾回收,而C/C++需要手动管理内存. 2.Lua使用动态

Lua教程(十七):C API简介_Lua

Lua是一种嵌入式脚本语言,即Lua不是可以单独运行的程序,在实际应用中,主要存在两种应用形式.第一种形式是,C/C++作为主程序,调用Lua代码,此时可以将Lua看做"可扩展的语言",我们将这种应用称为"应用程序代码".第二种形式是Lua具有控制权,而C/C++代码则作为Lua的"库代码".在这两种形式中,都是通过Lua提供的C API完成两种语言之间的通信的. 1. 基础知识: C API是一组能使C/C++代码与Lua交互的函数.其中包括读