0


Lua与C++交互(一)————堆栈

Lua与C++交互(一)————堆栈

Lua虚拟机

什么是Lua虚拟机

Lua本身是用C语言实现的,它是跨平台语言,得益于它本身的Lua虚拟机。

虚拟机相对于物理机,借助于操作系统对物理机器(CPU等硬件)的一种模拟、抽象,主要扮演CPU和内存的作用。

虚拟机的主要职责就是:执行字节码中的指令,管理全局状态(global_state)、数据栈(StackValue)和函数调用链状态(CallInfo)

可以理解成,lua虚拟机就是一个独立的空间,它会维护Lua的所有运行。

创建Lua虚拟机

使用C函数,luaL_newstate 来创建。

会创建一个lua_State的结构体,该结构体就代表了一个Lua虚拟机。

一个进程中可以创建多个Lua虚拟机,即多个lua_State结构。

Lua虚拟机中是单线程实现,所以,多个创建的Lua虚拟机之间是相互独立的。

cocos2dx中的创建Lua虚拟机的地方

AppDelegate中

boolAppDelegate::applicationDidFinishLaunching(){;;....// register lua moduleauto engine =LuaEngine::getInstance();;;...}

这里在调用单例LuaEngine的时候,会创建LuaStack

LuaEngine中

boolLuaEngine::init(void){
    _stack =LuaStack::create();
    _stack->retain();returntrue;}

LuaStack中

boolLuaStack::init(void){
    _state =lua_open();luaL_openlibs(_state);toluafix_open(_state);// Register our version of the global "print" functionconst luaL_Reg global_functions []={{"print", lua_print},{"release_print",lua_release_print},{nullptr,nullptr}};;;....}

其中成员变量_state的类型就是lua_State结构体,也就是Lua虚拟机。lua_open是函数luaL_newstate的宏定义。

同时可以得知,这里Lua虚拟机只有一个,这也是为什么在cocos2dx中需要严格按照规则来进行C++和Lua调用的原因。

lua_State

lua虚拟机对象,本身是一个结构体。

它是一个lua线程的执行状态,所有的C api都是基于这个结构体的。

structlua_State{
    CommonHeader;//#define CommonHeader
    GCObject *next; 
    lu_byte tt; 
    lu_byte marked
    lu_byte status;//虚拟机的错误状态码
    StkId top;//栈顶元素所在位置的下一个位置,也就是栈上第一个空闲的位置
    StkId base;//栈上,当前函数的基址(注意不是函数所在位置)
    global_State* l_G;//全局表,环境章节再说
    CallInfo* ci;//当前函数调用信息const Instruction* savedpc;//当前函数的指令位置,指向待取指指令的地址
    StkId stack_last;//栈最后一个位置的下一个位置
    StkId stack;//寄存器数组的起始位置
    CallInfo* end_ci;//函数调用信息数组的最后一个位置的下一个位置
    CallInfo* base_ci;//函数调用信息数组首地址int stacksize;//栈的大小int size_ci;//函数调用信息数组大小unsignedshort nCcalls;//内嵌C调用层数unsignedshort baseCcalls;//唤醒协程时的内嵌C调用层数
    lu_byte hookmask;
    lu_byte allowhook;int basehookcount;int hookcount;
    lua_Hook hook;
    TValue l_gt;//Global表
    TValue env;//环境表的临时位置
    GCObject* openupval;//open状态的upvalues
    GCObject* gclist;structlua_longjmp* errorJmp;//跳转信息单链表,实现try catch的功能,见函数章节
    ptrdiff_t errfunc;//当前错误处理函数在栈上的索引};

关于lua_State这里不过多阐述,感兴趣的可以看《lua设计与实现》这本书。

或者看看云风的《lua源码赏析》

或者看看这个博客
https://blog.csdn.net/yuanlin2008/category_1307277.html

Lua全局表

global_State 全局状态机

如果说lua_State是面对外面表现的虚拟机对象,那么global_State才是背后真正的大佬,该结构体不对外开放,即无法用Lua公开的API获取到它的指针、句柄或引用。

它里面有对主线程(lua_State实例)的引用、有全局字符串表、有内存管理函数、有GC需要的相关信息以及一切Lua在工作时需要的工作内存等等

想要深入了解,同样可以查看《lua设计与实现》这本书。

Lua堆栈

Lua的堆栈是Lua和C++交互的基础,也就是说C++和Lua之间的数据类型交互都是通过这个虚拟栈进行完成的。

不管是C++需要获取Lua的数据还是需要传递数据给Lua,都需要先将这个数据压入栈中。

在这里插入图片描述

从索引来说,分为正向和逆向索引。其中-1永远表示栈顶,1永远表示栈底。

入栈操作

涉及到一些Lua入栈的函数(常用)。
函数原型说明lua_pushnumbervoid lua_pushnumber (lua_State *L, lua_Number n)将数值类型n 压入栈中lua_pushnilvoid lua_pushnil (lua_State *L)将nil压入栈中lua_pushbooleanvoid lua_pushboolean (lua_State *L, int b);将布尔类型压入栈中lua_pushfstringconst char *lua_pushfstring (lua_State *L, const char *fmt, …)把一个格式化过的字符串压入堆栈,然后返回这个字符串的指针lua_pushintegervoid lua_pushinteger (lua_State *L, lua_Integer n)将一个整型数字n压入栈中lua_pushlstringvoid lua_pushlstring (lua_State *L, const char *s, size_t len)把指针 s 指向的长度为 len 的字符串压栈lua_pushstringvoid lua_pushstring (lua_State *L, const char *s)把指针 s 指向的以零结尾的字符串压栈lua_pushthreadint lua_pushthread (lua_State *L)把 L 中提供的线程压栈。 如果这个线程是当前状态机的主线程的话返回 1lua_pushvaluevoid lua_pushvalue (lua_State *L, int index)把堆栈上给定有效处索引处的元素作一个拷贝压栈lua_pushlightuserdatavoid lua_pushlightuserdata (lua_State *L, void *p)把一个 light userdata 压栈。 userdata 在 Lua 中表示一个 C 值。light userdata 表示一个指针。它是一个像数字一样的值:你不需要专门创建它,它也没有独立的 metatable ,而且也不会被收集(因为从来不需要创建)。只要表示的 C 地址相同,两个 light userdata 就相等lua_pushcfunctionvoid lua_pushcfunction (lua_State *L, lua_CFunction f)将一个 C 函数压入堆栈。 这个函数接收一个 C 函数指针,并将一个类型为 function 的 Lua 值 压入堆栈。当这个栈顶的值被调用时,将触发对应的 C 函数
具体可以查看

https://www.w3cschool.cn/doc_lua_5_1/lua_5_1-index.html#lua_pushnumber

取值和出栈

与之对应的取值为:

lua_to*(lua_State * L,栈中位置)取值

对应的出栈为:

lua_pop(lua_State * L,出栈个数)出栈

举例

myName = “beauty girl”

在这里插入图片描述

  1. C++想要获取myName的值,根据规则,它需要把myName压入栈中,这样lua就能看到;
  2. lua从堆栈中获取myName的值,此时栈顶为空;
  3. lua拿着myName去全局表中查找与之对应的字符串;
  4. 全局表找到,并返回"beauty girl";
  5. lua把"beauty girl"压入栈中;
  6. C++从栈中获取"beauty girl"
标签: lua c++ cocos2d

本文转载自: https://blog.csdn.net/canjiangmengyuan/article/details/132410940
版权归原作者 浮生述梦 所有, 如有侵权,请联系我们删除。

“Lua与C++交互(一)————堆栈”的评论:

还没有评论