浅析C\C++和Lua的通信方式

 更新时间:2014年09月18日 12:04:32   投稿:hebedich  
lua作为小巧精悍的脚本语言,易于嵌入c/c++中 , 广泛应用于游戏AI ,实际上在任何经常变化的逻辑上都可以使用lua实现,配合c/c++实现的底层接口服务,能够大大降低系统的维护成本。

为了实现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而言,不会检查值是否为数字类型,而是检查值是否能转换为数字类型。

如有任何疑问和建议,欢迎指出讨论,谢谢~

相关文章

  • Lua极简入门指南(一):函数篇

    Lua极简入门指南(一):函数篇

    这篇文章主要介绍了Lua极简入门指南(一):函数篇,本文讲解了函数的定义、函数多值返回、变长参数、闭包(closures)等内容,需要的朋友可以参考下
    2014-10-10
  • Lua中的函数相关知识点整理汇总

    Lua中的函数相关知识点整理汇总

    这篇文章主要介绍了Lua中的函数相关知识点整理汇总,包括函数的参数传递和定义函数等基本知识,需要的朋友可以参考下
    2015-05-05
  • Lua在windows下的安装及环境配置

    Lua在windows下的安装及环境配置

    这篇文章主要介绍了Lua在windows下的安装及环境配置,本文使用lua for windows整体环境,lua for windows其实是一整套Lua的开发环境,需要的朋友可以参考下
    2015-07-07
  • lua读取redis数据的null判断示例代码

    lua读取redis数据的null判断示例代码

    最近在工作中遇到了一个问题,通过查找相关资料才得知原因是因为返回结果的问题,下面这篇文章主要给大家介绍了关于lua读取redis数据的null判断的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2018-09-09
  • Lua中的控制结构(流程控制)简明总结

    Lua中的控制结构(流程控制)简明总结

    这篇文章主要介绍了Lua中的控制结构(流程控制)简明总结,本文讲解了IF、repeat、while、for、break、return等语句,需要的朋友可以参考下
    2014-10-10
  • 在Lua中使用模块的基础教程

    在Lua中使用模块的基础教程

    这篇文章主要介绍了在Lua中模块的基本使用方法,是Lua入门学习中的基础知识,需要的朋友可以参考下
    2015-05-05
  • Lua所有内置函数罗列

    Lua所有内置函数罗列

    这篇文章主要介绍了Lua所有内置函数罗列,本文汇集了Lua脚本语言的所有内置函数,需要的朋友可以参考下
    2015-04-04
  • Lua获取系统时间和时间格式化方法及格式化参数

    Lua获取系统时间和时间格式化方法及格式化参数

    这篇文章主要介绍了Lua获取系统时间和时间格式化方法及格式化参数,需要的朋友可以参考下
    2015-04-04
  • Lua UnPack函数用法实例

    Lua UnPack函数用法实例

    这篇文章主要介绍了Lua UnPack函数用法实例,unpack它接受一个数组(table)作为参数,并默认从下标1开始返回数组的所有元素,需要的朋友可以参考下
    2015-04-04
  • Lua中的迭代器(iterator)浅析

    Lua中的迭代器(iterator)浅析

    这篇文章主要介绍了Lua中的迭代器(iterator)浅析,本文讲解了pairs迭代器和、ipairs迭代器,同时提及了io.lines、string.gmatch、迭代器与Closure(闭包)等内容,需要的朋友可以参考下
    2014-09-09

最新评论