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中

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

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

LuaEngine中

bool LuaEngine::init(void)
{_stack = LuaStack::create();_stack->retain();return true;
}

LuaStack中

bool LuaStack::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都是基于这个结构体的。

struct lua_State
{CommonHeader;//#define CommonHeaderGCObject *next; lu_byte tt; lu_byte markedlu_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;//函数调用信息数组大小unsigned short nCcalls;//内嵌C调用层数unsigned short baseCcalls;//唤醒协程时的内嵌C调用层数lu_byte hookmask;lu_byte allowhook;int basehookcount;int hookcount;lua_Hook hook;TValue l_gt;//Global表TValue env;//环境表的临时位置GCObject* openupval;//open状态的upvaluesGCObject* gclist;struct lua_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 中提供的线程压栈。 如果这个线程是当前状态机的主线程的话返回 1
lua_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"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/99896.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

6-3 使用函数输出水仙花数

分数 20 全屏浏览题目 切换布局 作者 张高燕 单位 浙大城市学院 水仙花数是指一个N位正整数(N≥3),它的每个位上的数字的N次幂之和等于它本身。例如:153135333。 本题要求编写两个函数,一个判断给定整数是否水仙花数…

开源数据库Mysql_DBA运维实战 (总结)

开源数据库Mysql_DBA运维实战 (总结) SQL语句都包含哪些类型 DDL DCL DML DQL Yum 安装MySQL的配置文件 配置文件:/etc/my.cnf日志目录:/var/log/mysqld.log错误日志:/var/log/mysql/error.log MySQL的主从切换 查看主…

安装Ubuntu服务器、配置网络、并安装ssh进行连接

安装Ubuntu服务器、配置网络、并安装ssh进行连接 1、配置启动U盘2、配置网络3、安装ssh4、修改ssh配置文件5、重启电脑6、在远程使用ssh连接7、其他报错情况 1、配置启动U盘 详见: U盘安装Ubuntu系统详细教程 2、配置网络 详见:https://blog.csdn.net/davidhzq/a…

16、Flink 的table api与sql之连接外部系统: 读写外部系统的连接器和格式以及FileSystem示例(1)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

linux-进程

文章目录 1.先谈硬件冯诺依曼体系结构 2.再谈软件操作系统什么是操作系统?为什么要有操作系统?如何管理?系统调用 3.再谈进程那么具体Linux是怎么做的?指令 ps ajx 查看所有进程 非实时top 实时查看进程 相当于任务管理器ls /proc 内存级进程…

Linux命令200例:tar命令主要用于创建、查看和提取归档文件(常用)

🏆作者简介,黑夜开发者,全栈领域新星创作者✌。CSDN专家博主,阿里云社区专家博主,2023年6月csdn上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 &…

idea 左下角的Git(Version Control)中显示Local Changes窗口

打开Local Changes窗口来查看当前Git仓库的本地变更。 使用快捷键: - Windows: Alt9 - Mac: Cmd9 解决: (1)idea打开settings (2)点击Version Control窗口选项卡,选择Commit选项,对 Use.... in…

STM32使用定时器实现微秒(us)级延时

STM32使用定时器实现微秒(us)级延时 引言前期准备介绍系统时钟定时器时钟 项目项目介绍STM32CubeMX程序 引言 目前开发STM32普遍使用HAL库,但 HAL 库封装的延时函数目前仅支持 ms 级别的延时,日常很多情况下会用到 us 延时&#…

字符设备驱动实例(PWM和RTC)

目录 五、PWM 六、RTC 五、PWM PWM(Pulse Width Modulation,脉宽调制器),顾名思义就是一个输出脉冲宽度可以调整的硬件器件,其实它不仅脉冲宽度可调,频率也可以调整。它的核心部件是一个硬件定时器,其工作原理可以用…

Midjourney API 国内申请及对接方式

在人工智能绘图领域,想必大家听说过 Midjourney 的大名吧! Midjourney 以其出色的绘图能力在业界独树一帜。无需过多复杂的操作,只要简单输入绘图指令,这个神奇的工具就能在瞬间为我们呈现出对应的图像。无论是任何物体还是任何风…

8月18日上课内容 Haproxy搭建Web群集

本章结构 课程大纲 Haproxy调度算法 常见的web集群调度器 目前常见的Web集群调度器分为软件和硬件软件 通常使用开源的LVS、Haproxy、Nginx 硬件一般使用比较多的是F5,也有很多人使用国内的一些产品,如梭子鱼、绿盟等 Haproxy应用分析 LVS在企业应用中…

两两交换链表中的节点

你存在,我深深的脑海里~ 题目: 示例: 思路: 这个题有点类似于反转一个单链表,不同的地方在于这个题不全反转,所以我们不同的地方在于此题多用了一个prve指针保存n1的前一个节点,以及头的改变&a…

什么是KNN( K近邻算法)

什么是KNN( K近邻算法) 虽然名字中有NN,KNN并不是哪种神经网络,它全名K-Nearest-Neighbors:K近邻算法,是机器学习中常用的分类算法。 物以类聚,人以群分。KNN的基础思想很简单,要判断一个新数据的类别&…

Lucky player —— Java 项目(Spring Boot)

一、项目介绍 项目名称:lucky player 项目的主要功能:本系统主要功能为构建了一个用户分享音乐的平台,普通用户不进行登录即可收听其他用户已经发布的专辑中的音乐。 作为博主则可以在该平台上传音频,以及在线音频录制上传。音频上…

MySQL数据库中间件Mycat介绍及下载安装(教程)

一,介绍 MyCat是开源的、活跃的、基于Java语言编写的MySQL数据库中间件。可以像使用MySQL一样来使用MyCat,对于开发人员来说根本感觉不到MyCat的存在。 开发人员只需要连接MyCat即可,而具体底层用到几台数据库,每一台数据库服务器…

GNU GRUB version 2.06 Minimal Bash-lke line editing is supported 问题修复

一、问题背景 博主喜欢折腾系统,电脑原来有一个windows系统,想整一个Linux双系统,结果开机时出现以下画面: GNU GRUB version 2.06 Minimal Bash-lke line editing is supported. TAB lists possible comand completions, Anywh…

vue2.x项目从0到1(七)之用户权限

此章节偏理论知识 对于小一点的项目 比如说角色都是平级的 那我们直接像之前 vue2.x项目从0到1(二)之后台管理侧边栏(动态渲染路由以及高亮)_vue动态渲染侧边栏_关忆北_的博客-CSDN博客这样渲染就行了 但是一旦项目大了 …

MongoDB基本使用

在 MongoDB 中我们可以使用use命令来创建数据库,如果该数据库不存在,则会创建一个新的数据库,如果该数据库已经存在,则将切换到该数据库。使用use命令创建数据库的语法格式如下: --use database_name use my_db1;数据…

Java并发编程之线程池详解

目录 🐳今日良言:不悲伤 不彷徨 有风听风 有雨看雨 🐇一、简介 🐇二、相关代码 🐼1.线程池代码 🐼2.自定义实现线程池 🐇三、ThreadPoolExecutor类 🐳今日良言:不悲伤 不彷徨 有风听风 有…

浅析Python爬虫ip程序延迟和吞吐量影响因素

作为一名资深的爬虫程序员,今天我们很有必要来聊聊Python爬虫ip程序的延迟和吞吐量,这是影响我们爬取效率的重要因素。这里我们会提供一些实用的解决方案,让你的爬虫程序飞起来! 网络延迟 首先,让我们来看看网络延迟对…