【Lua之·Lua与C/C++交互·Lua CAPI访问栈操作】

news2024/12/27 17:30:34

系列文章目录


文章目录

  • 前言
  • 一、概述
    • 1.1 Lua堆栈
  • 二、栈操作
    • 2.1 基本的栈操作
    • 2.2 入栈操作函数
    • 2.3 出栈操作函数
    • 2.4 既入栈又出栈的操作函数
    • 2.5 栈检查与类型转换函数
    • 2.5 获取表数据
  • 三、实例演示
  • 总结


前言

  Lua是一种轻量级的、高性能的脚本语言,经常被用于游戏开发、嵌入式系统和其他需要灵活、可扩展的脚本功能的应用程序中。


一、概述

  • Lua是一种解释型语言,它具有简单的语法和动态类型系统,使得它易于学习和使用。它的设计目标是成为一种嵌入式脚本语言,在C/C++程序中作为库使用。这使得Lua非常适用于游戏开发,因为它可以与其他编程语言结合使用,提供灵活的脚本功能。

  • Lua的另一个重要特点是它的高性能。与其他动态语言相比,Lua的执行速度非常快,这得益于它的精简设计和高度优化的虚拟机。这使得Lua在游戏中处理大量的数据和逻辑时表现突出。

  • 除了高性能外,Lua还具有一些其他的优势。首先,它具有简洁而灵活的语法,使得编写Lua代码变得非常简单和直观。其次,Lua提供了强大的元表和闭包功能,使得它可以实现面向对象编程和函数式编程的高级特性。最后,Lua还具有可扩展性,可以通过编写C/C++扩展模块来增强其功能。

1.1 Lua堆栈

在这里插入图片描述

要理解Lua和C++交互,首先要理解Lua堆栈。

  • Lua和C/C++语言通信的主要方法是一个无处不在的虚拟栈。栈的特点是先进后出

  • 在Lua中,Lua堆栈就是一个struct,堆栈索引的方式可是是正数也可以是负数,区别是:正数索引1永远表示栈底,负数索引-1永远表示栈顶。

规则:

①若Lua虚拟机堆栈里有N个元素,则可以用 1 ~ N 从栈底向上索引,也可以用 -1 ~ -N 从栈顶向下索引,一般后者更加常用
②堆栈的每个元素可以为任意复杂的Lua数据类型,堆栈中没有元素的空位,隐含为包含一个“空”类型数据

特性:
若有4个元素分别入栈,则:

①. 正数索引,栈底是1,然后一直到栈顶是逐渐+1,最后变成4(4大于1)
②. 负数索引,栈底是-4,然后一直到栈顶是逐渐+1,最后变成-1(-1大于-4)

索引相关:

①. 正数索引,不需要知道栈的大小,我们就能知道栈底在哪,栈底的索引永远是1
②. 负数索引,不需要知道栈的大小,我们就能知道栈顶在哪,栈顶的索引永远是-1

二、栈操作

2.1 基本的栈操作

函数描述
lua_push*将一个值压入栈顶。例如,lua_pushnil、lua_pushboolean、lua_pushnumber等。
lua_gettop获取栈顶的索引,也就是栈中元素的数量。
lua_settop设置新的栈顶索引,可以-push、pop或者修改栈中的元素数量。
lua_remove移除指定的元素。
lua_insert将栈顶元素插入到指定位置。
lua_pop弹出指定数量的元素。
lua_settop(L, index)将栈顶设置为特定索引,这样栈上索引为index的位置就是当前的“虚拟”栈顶。
lua_to***函数获取值。
lua_set***函数设置值。

2.2 入栈操作函数

这些函数会将值压入 Lua 栈中,通常是执行某些操作后产生的结果或初始化时需要的值。

函数描述
lua_pushnil(L)将 nil 值压入栈中。
lua_pushnumber(L, n)将一个数字 n 压入栈中。
lua_pushinteger(L, n)将一个整数 n 压入栈中。
lua_pushlstring(L, s, len)将一个长度为 len 的字符串 s 压入栈中。
lua_pushstring(L, s)将一个字符串 s 压入栈中(等同于 lua_pushlstring,len 会自动计算)。
lua_pushcclosure(L, f, n)将 C 函数 f 与 n 个 Lua 环境变量封装成闭包,压入栈中。
lua_pushboolean(L, b)将布尔值 b(0 或 1)压入栈中。
lua_pushlightuserdata(L, p)将一个指针 p 压入栈中(通常用于存储非 Lua 数据)。
lua_pushthread(L)将当前线程(协程)压入栈中。
lua_newtable(L)创建一个新的表并将其压入栈中。
lua_createtable(L, narr, nrec)创建一个新的表并将其压入栈中,narr 和 nrec 为初始数组和哈希部分的容量。
lua_newuserdata(L, size)创建一个新的用户数据块,并将其指针压入栈中。
luaL_newmetatable(L, tname)创建一个新的元表并将其压入栈中。
lua_getglobal(L, name)获取全局变量 name 的值并将其压入栈中。
lua_gettable(L, idx)将表 idx 中与栈顶值相对应的值压入栈中。
lua_getfield(L, idx, k)获取表 idx 中字段 k 的值并将其压入栈中。
lua_rawget(L, idx)从表 idx 中获取原始值并压入栈中(不调用元方法)。
lua_rawgeti(L, idx, n)从表 idx 中按整数索引 n 获取值并压入栈中。
lua_rawgetp(L, idx, p)从表 idx 中按指针索引 p 获取值并压入栈中。
luaL_loadfile(L, filename)加载 Lua 文件并将其作为函数压入栈中。
luaL_loadstring(L, s)加载 Lua 字符串并将其作为函数压入栈中。
luaL_loadbuffer(L, buff, size, name)加载一个缓冲区并将其作为 Lua 函数压入栈中。
luaL_newstate()创建一个新的 Lua 状态,并为其分配一个新的栈。

2.3 出栈操作函数

这些函数会将栈中的值弹出,以进行操作或清理栈。

函数描述
lua_pop(L, n)从栈中弹出 n 个元素。
lua_remove(L, idx)删除索引为 idx 处的值,并将栈中其上方的元素向下移动。
lua_replace(L, idx)将栈顶的值替换为索引 idx 处的值,栈顶元素被弹出。
lua_setglobal(L, name)将栈顶的值设置为全局变量 name 的值,并从栈中弹出。
lua_settable(L, idx)将栈顶的值设置为 idx 处表中的一个字段,并弹出键和值。
lua_setfield(L, idx, k)将栈顶的值设置为 idx 处表中的字段 k 的值,并弹出键和值。
lua_rawset(L, idx)将栈顶的值设置为 idx 处表中的一个字段(原始设置,不调用元方法)。
lua_rawseti(L, idx, n)将栈顶的值设置为 idx 处表中的键为整数 n 的字段。
lua_rawsetp(L, idx, p)将栈顶的值设置为 idx 处表中的键为指针 p 的字段。
lua_setmetatable(L, idx)将栈顶的值设置为 idx 处值的元表,并从栈中弹出元表。
lua_setuservalue(L, idx)将栈顶的值设置为 idx 处用户数据的用户值,并从栈中弹出值。
luaL_unref(L, idx, ref)释放引用 ref 指向的值,并将其从栈中弹出。

2.4 既入栈又出栈的操作函数

这些函数同时进行入栈和出栈操作。

函数描述
lua_getmetatable(L, idx)获取索引 idx 处值的元表(如果存在),并将其压入栈中;如果没有元表,栈不变。
lua_next(L, idx)获取索引 idx 处表的下一个键值对,并将键和值压入栈中,弹出上一个键。
lua_concat(L, n)将栈顶的 n 个字符串拼接起来,结果压入栈中,弹出原始字符串。
lua_call(L, nargs, nresults)调用栈顶的函数并弹出 nargs 个参数,返回 nresults 个结果压入栈中。
lua_pcall(L, nargs, nresults, errfunc)与 lua_call 类似,但支持错误处理,调用失败时错误信息压入栈中。
luaL_callmeta(L, idx, e)调用元表中字段为 e 的元方法,将栈顶的值作为参数传递,并将返回值压入栈中。

2.5 栈检查与类型转换函数

这些函数用于检查栈中的元素类型或将栈中的元素转换为特定类型。

函数描述
lua_isnil(L, idx)检查索引 idx 处的值是否为 nil。
lua_isboolean(L, idx)检查索引 idx 处的值是否为布尔值。
lua_isnumber(L, idx)检查索引 idx 处的值是否为数字。
lua_isstring(L, idx)检查索引 idx 处的值是否为字符串。
lua_istable(L, idx)检查索引 idx 处的值是否为表。
lua_isfunction(L, idx)检查索引 idx 处的值是否为函数。
lua_tonumber(L, idx)将栈中 idx 处的值转换为数字,如果不行返回 0。
lua_tointeger(L, idx)将栈中 idx 处的值转换为整数,如果不行返回 0。
lua_toboolean(L, idx)将栈中 idx 处的值转换为布尔值。
lua_tostring(L, idx)将栈中 idx 处的值转换为字符串。
lua_topointer(L, idx)将栈中 idx 处的值转换为指针。
lua_type(L, idx)获取栈中 idx 处的值的类型。

2.5 获取表数据

函数描述
lua_getfield(L, t_idx, key)从 Lua 栈上的一个表中,根据字段名(key)获取对应的值,并将这个值压入 Lua 栈顶

注意: Lua 可以高效地进行数据传递、类型转换和函数调用等操作。在实际编程中,开发者需要注意栈的管理,确保栈操作符合预期,以避免栈溢出或数据丢失等问题。

三、实例演示

示例1:

lua_State *L = luaL_newstate();
luaL_openlibs(L);
// 将值推入栈中
lua_pushnumber(L, 123);
lua_pushstring(L, "Hello, World");
// 设置栈顶索引为1,即栈中第二个元素
lua_settop(L, 1);
qDebug() << "栈顶索引" << lua_gettop(L);
qDebug() << "1" << lua_tostring(L,1);
qDebug() << "2" << lua_tostring(L,2);
qDebug() << "-2" << lua_tostring(L,-2);
qDebug() << "-1" << lua_tostring(L,-1);

qDebug() << "消费堆栈----------start";
lua_pop(L,1);
qDebug() << (int)lua_tointeger(L, 1);
qDebug() << lua_tostring(L, 0);
qDebug() << "消费堆栈----------end";

// 获取并打印第二个元素
if (lua_isnumber(L, 1)) {
    printf("The second element is a number: %d\n", (int)lua_tointeger(L, 1));
    qDebug() << (int)lua_tointeger(L, 1);
    qDebug() << lua_tostring(L, 0);
}
// 替换第二个元素为新的字符串
lua_pushstring(L, "New string");
lua_replace(L, 1);
// 再次设置栈顶
lua_settop(L, 1);
// 获取并打印修改后的第二个元素
if (lua_isstring(L, 1)) {
    printf("The second element is now a string: %s\n", lua_tostring(L, 1));
}
// 清理Lua状态机
lua_close(L);

运行结果:
在这里插入图片描述

示例2:

lua_State *L = luaL_newstate();
luaL_openlibs(L);
// Push values onto the stack
lua_pushstring(L, "Hello");
lua_pushnumber(L, 123);
// Get the stack top index
int stack_top = lua_gettop(L);
printf("Stack top index: %d\n", stack_top);
// Set the stack top to a specific index
lua_settop(L, 5); // Pushes nil values to make the stack size 5
qDebug() << "栈大小:" << lua_gettop(L);
qDebug() << lua_tostring(L,-1);
qDebug() << lua_tostring(L,-2);
qDebug() << lua_tostring(L,-3);
qDebug() << lua_tostring(L,-4);
qDebug() << lua_tostring(L,-5);
qDebug() << "---------------";
// Remove an element
lua_remove(L, -1); // Removes the second element from the top (-2 because of the nil values)
qDebug() << "栈大小:" << lua_gettop(L);
qDebug() << lua_tostring(L,-1);
qDebug() << lua_tostring(L,-2);
qDebug() << lua_tostring(L,-3);
qDebug() << lua_tostring(L,-4);
qDebug() << lua_tostring(L,-5);
qDebug() << "---------------";
// Insert an element
lua_pushstring(L, "World");
lua_insert(L, -2); // Inserts the string "World" before the top element
qDebug() << "栈大小:" << lua_gettop(L);
qDebug() << lua_tostring(L,-1);
qDebug() << lua_tostring(L,-2);
qDebug() << lua_tostring(L,-3);
qDebug() << lua_tostring(L,-4);
qDebug() << lua_tostring(L,-5);
qDebug() << "---------------";
//Replace an element
lua_pushstring(L, "New string");
lua_replace(L, -3); // Replace the string "World" before the top element
qDebug() << lua_tostring(L,-1);
qDebug() << lua_tostring(L,-2);
qDebug() << lua_tostring(L,-3);
qDebug() << lua_tostring(L,-4);
qDebug() << lua_tostring(L,-5);
qDebug() << "---------------";
// Pop elements
lua_pop(L, 2); // Pops the top two elements
qDebug() << "栈大小:" << lua_gettop(L);
qDebug() << lua_tostring(L,-1);
qDebug() << lua_tostring(L,-2);
qDebug() << lua_tostring(L,-3);
qDebug() << lua_tostring(L,-4);
qDebug() << lua_tostring(L,-5);
qDebug() << "---------------";
lua_close(L);

运行结果:
在这里插入图片描述

示例3:


运行结果:


总结

  Lua是一种轻量级、高性能的脚本语言,适用于游戏开发、嵌入式系统和其他需要灵活、可扩展的脚本功能的应用程序。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux -- 生产消费模型

目录 概念 代码 BlockQueue.hpp 代码&#xff1a; 伪唤醒&#xff01;&#xff01; Thread.hpp 代码&#xff1a; Task.hpp 代码&#xff1a; test.cc 代码&#xff1a; 再次理解 概念 生产消费模型&#xff0c;也称为生产者-消费者问题&#xff0c;是计算机科学中的一…

DevOps实战:用Kubernetes和Argo打造自动化CI/CD流程(1)

DevOps实战&#xff1a;用Kubernetes和Argo打造自动化CI/CD流程&#xff08;1&#xff09; 架构 架构图 本设计方案的目标是在一台阿里云ECS服务器上搭建一个轻量级的Kubernetes服务k3s节点&#xff0c;并基于Argo搭建一套完整的DevOps CI/CD服务平台&#xff0c;包括Argo CD…

React 第二十节 useRef 用途使用技巧注意事项详解

简述 useRef 用于操作不需要在视图上渲染的属性数据&#xff0c;用于访问真实的DOM节点&#xff0c;或者React组件的实例对象&#xff0c;允许直接操作DOM元素或者是组件&#xff1b; 写法 const inpRef useRef(params)参数&#xff1a; useRef(params)&#xff0c;接收的 …

【2024最新】基于Python+Mysql+django的水果销售系统Lw+PPT

作者&#xff1a;计算机搬砖家 开发技术&#xff1a;SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;Java精选实战项…

利用Java爬虫速卖通按关键字搜索AliExpress商品

在这个信息爆炸的时代&#xff0c;数据的价值日益凸显。对于电商领域的从业者来说&#xff0c;能够快速获取商品信息成为了一项重要的技能。速卖通&#xff08;AliExpress&#xff09;作为全球领先的跨境电商平台&#xff0c;拥有海量的商品数据。本文将介绍如何使用Java语言编…

动态规划<五> 子数组问题(含对应LeetcodeOJ题)

目录 引例 经典LeetcodeOJ题 1.第一题 2.第二题 3.第三题 4.第四题 5.第五题 6.第六题 7.第七题 引例 OJ传送门 Leetcode<53> 最大子数组和 画图分析: 使用动态规划解决 1.状态表示 dp[i]表示以i位置为结尾的所有子数组中的最大和 2.状态转移方程 子数组的问题可以…

前端实现PDF预览的几种选择(pdfjs-dist、react-pdf、pdf-viewer)

记录 PDF预览的选型 对于浏览器自带的PDF预览 如果能直接使用&#xff0c;那自然最好不过了&#xff0c;但考虑多种因素&#xff0c;比如权限问题&#xff0c;禁止用户去下载PDF、预览样式不统一&#xff08;不同浏览器PDF预览的实现不同&#xff09;&#xff0c;所有最终放弃…

小米路由器开启SSH,配置阿里云ddns,开启外网访问SSH和WEB管理界面

文章目录 前言一、开启SSH二、配置阿里云ddns1.准备工作2.创建ddns脚本3.添加定时任务 三、开启外网访问SSH和WEB管理界面1、解除WEB管理页面访问限制2.手动添加防火墙端口转发规则&#xff0c;开启外网访问WEB管理和SSH 前言 例如&#xff1a;随着人工智能的不断发展&#xf…

机器学习(三)-多项式线性回归

文章目录 1. 多项式回归理论2. python通过多项式线性回归预测房价2.1 预测数据2.2导入标准库2.3 导入数据2.4 划分数据集2.5 构建二次多项式特征&#xff08;1, x, x^2&#xff09;2.6 导入线性回归模块2.7 对测试集进行预测2.8 计算均方误差 J2.9 计算参数 w0、w1、w22.10 可视…

【再学javascript算法之美】前端面试频率比较高的基础算法题

基础算法题练习代码&#xff0c;看看能做出几道题 代码实现 找出字符串中出现次数最多的字符 const array "cncnansdnajsadnjasndjnasjdnjj";// 找出出现次数最多的字符 let obj {}; for (let index 0; index < array.length; index) {const element array[…

芯产品|暴雨推出基于兆芯晶片的新品台式机

近期&#xff0c;基于兆芯开先KX-7000系列处理器&#xff0c;暴雨推出新品桌面整机TSJ200-ZX&#xff0c;凭借开先KX-7000系列处理器强劲的性能表现和优异的兼容性&#xff0c;将为行业信创深入发展增添更多的活力和能量。 暴雨TSJ200-ZX是针对政务办公&#xff0c;金融机构和…

echarts进度仪表盘形式

const pointerData 55; // 仪表指针数据const steps 10; // 总共10个步骤 const borderColor {colorStops: [{offset: 0,color: rgba(208, 244, 255, 1)}, {offset: 1,color: rgba(35, 190, 240, 1)}] }; // 边框颜色// 使用数组和循环动态生成颜色数组 const axisLinecolor…

代码随想录-笔记-其八

让我们开始&#xff1a;动态规划&#xff01; 70. 爬楼梯 - 力扣&#xff08;LeetCode&#xff09; 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; class Solution { public:int climbStairs(i…

线性回归a

训练数据 求平方损失的平均值1/n&#xff0c;目标求解w&#xff0c;b使得损失函数最小 显示解

学习记录—正则表达式-基本语法

正则表达式简介-《菜鸟教程》 正则表达式是一种用于匹配和操作文本的强大工具&#xff0c;它是由一系列字符和特殊字符组成的模式&#xff0c;用于描述要匹配的文本模式。 正则表达式可以在文本中查找、替换、提取和验证特定的模式。 本期内容将介绍普通字符&#xff0c;特殊…

利用AI优化SEO关键词提升网站流量的有效策略

内容概要 在数字化时代&#xff0c;网站流量的增加对于任何企业或个人至关重要。为了在竞争激烈的市场中吸引更多用户&#xff0c;优化网站的SEO关键词显得尤为重要。随着人工智能技术的迅猛发展&#xff0c;它在SEO领域的应用也逐渐渗透&#xff0c;为关键词优化提供了新的可…

敏捷开发05:Sprint Planning 冲刺计划会议详细介绍和用户故事拆分、开发任务细分

Sprint Planning 冲刺计划会议简介 Sprint Planning &#xff08;冲刺计划会议&#xff09;&#xff0c;又叫规划会议。此会议通过 Scrum 团队的集体沟通讨论&#xff0c;确定接下来的 Sprint 中要完成的待开发项&#xff0c;把它们组成一个 Sprint Backlog。这些待开发项都是…

极简容器云WeKube快速体验

极简容器云WebKube快速体验 WeKube是什么&#xff1f; 概述 WeKube 是一个基于 Kubernetes 构建的极简Serverless容器服务&#xff0c;它提供了一个简单直观的方式来部署、管理和监控容器化的应用程序。WeKube 的目标是让用户无需关心底层基础设施的具体细节&#xff0c;而是…

Java开发经验——数据库开发经验

摘要 本文主要介绍了Java开发中的数据库操作规范&#xff0c;包括数据库建表规范、索引规约、SQL规范和ORM规约。强调了在数据库设计和操作中应遵循的最佳实践&#xff0c;如字段命名、数据类型选择、索引创建、SQL语句编写和ORM映射&#xff0c;旨在提高数据库操作的性能和安…

ovirt-engine登录报错

ovirt-engine登录报错 注&#xff1a;用户名不是admin&#xff0c;而是adminlocalhost