Lua学习笔记:C/C++和Lua的相互调用

news2024/10/7 10:21:54
前言
本篇在讲什么

C/C++和Lua的相互调用
本篇适合什么

适合初学Lua的小白
适合需要C/C++和lua结合开发的人

本篇需要什么

Lua语法有简单认知
C/C++语法有简单认知
依赖Lua5.1的环境
依赖VS 2017编辑器

本篇的特色

具有全流程的图文教学
重实践,轻理论,快速上手
提供全流程的源码内容


★提高阅读体验★

👉 ♠ 一级标题 👈

👉 ♥ 二级标题 👈

👉 ♣ 三级标题 👈

👉 ♦ 四级标题 👈


目录

  • ♠ 为什么C/C++和Lua可以相互调用
  • ♠ 为什么要C/C++和Lua相互调用
  • ♠ Lua的C API
    • ♥ 加载标准库
  • ♠ C++和Lua的相互调用
    • ♥ 数据交换
    • ♥ 执行Lua脚本
      • ♣ 引入头文件
      • ♣ Lua的虚拟机
      • ♣ 注册库
    • ♥ C++和Lua的数据交互
      • ♣ C++调用Lua方法传递参数
      • ♣ Lua调用C++方法
  • ♠ C API一些常见函数
    • ♥ 压入数据
    • ♥ 查询数据
    • ♥ 其他栈操作
  • ♠ 推送
  • ♠ 结语


♠ 为什么C/C++和Lua可以相互调用

Lua运行的解释器是用Lua标准库实现的独立解释器,所以Lua是一种嵌入型语言,可以被当做库来拓展其他应用

Lua可以通过固定的C API实现和C语言的交互


♠ 为什么要C/C++和Lua相互调用

Lua作为脚本语言,不需要预先编译,加上其语法简单扩展性强的特点,尝尝作为胶水去完成其他应用的拓展,例如常见使用Lua作为热更的解决方案

Lua存在自身的局限性,通过调用C/C++编写的外部库,可以实现Lua不方便实现的功能,或实现效率更高的方式


♠ Lua的C API

C API是一个函数、常量和类型组成的集合,有了它,C语言代码就能与Lua语言交互
C API包括读写Lua全局变量的函数、调用Lua函数的函数、运行Lua代码段的函数,以及注册C函数(以便于其后可被Lua代码调用)的函数等
通过调用C API, C代码几乎可以做到Lua代码能够做的所有事情


♥ 加载标准库

如果你本地安装有Lua环境,可以很简单的在项目内加载Lua的标准库,下面文章可以了解如何在vs中引入lua的标准库

VIsual Studio内引用Lua解释器,编译Lua源码,执行Lua脚本


♠ C++和Lua的相互调用

我们尝试性的使用C++去加载一个lua文件,并一点点去解释和理解其中每个步骤的作用


♥ 数据交换

首先我们需要知道的是Lua和C之间的通信通过虚拟栈(stack)
当我们想要从Lua获取一个值(例如一个全局变量)时,会经过以下过程

  • C获取Lua的值

需要调用Lua将指定的值压入栈中,C再去栈中获取

  • Lua获取C的值

首先通过C将这个值压入栈,然后调用Lua将其从栈中弹出即可

在这里插入图片描述

如上图所示,交换数据都需要经过这个中间栈,数据交换的过程,就是入栈出栈的过程

栈的索引可以通过正数和负数表示,正数栈底索引1,负数栈顶为-1

C API提供了完善的接口让我们去操作对栈内数据的处理


♥ 执行Lua脚本

下面代码通过C++执行了一个名为Test.lua的Lua脚本

#include <iostream>

extern "C" {
	#include "lua.h"
	#include "lualib.h"
	#include "lauxlib.h"
}

int main()
{
	lua_State *L = luaL_newstate();
	luaL_openlibs(L);
	luaL_dofile(L, "Test.lua");   // 读取Lua文件,并压入栈内
	lua_close(L);                 // 关闭lua环境
	return 0;
}

♣ 引入头文件

lua.hlualib.hlauxlib.h三个头文件,是Lua标准库下调用Lua接口的文件

  • lua.h

头文件lua.h声明了Lua提供的基础函数
包括创建新Lua环境的函数、调用Lua函数的函数、读写环境中的全局变量的函数,以及注册供Lua语言调用的新函数的函数等
lua.h声明的所有内容都有一个前缀lua_(例如lua_pcall)

简单的理解,所有外部调用Lua和Lua调用外部都是使用lua.h内接口对应的功能

  • lualib.h

头文件lauxlib.h声明了辅助库所提供的函数
辅助库使用lua.h提供的基础API来提供更高层次的抽象,特别是对标准库用到的相关机制进行抽象
其中所有的声明均以luaL_开头(例如lual_loadstring)

简单的理解,lauxlib.h是对lua.h提供功能的封装

  • lauxlib.h

所有lua相关功能以单独的包存在(例如io、math)
lua运行环境创建后,不包含任何预定义的函数
需要用到哪些功能通过lauxlib.h内的接口注册

简单的理解,lua运行环境初始时没有任何功能的,想用啥功能,用lauxlib.h注册一下才能用


♣ Lua的虚拟机

我们通过luaL_newstate()方法创建了一个Lua虚拟机

lua_State *L = luaL_newstate();

lua_State是一个结构体,存储了一个Lua程序的执行状态信息,Lua和C程序通信的栈就存储在其中

注:这里先知道他是干嘛的就行了,后面有机会我们再去分析Lua的源码


♣ 注册库

上文我们已经提到了,Lua新创建的环境中是没有任何函数定义的,我们需要注册,luaL_openlibs方法就是打开所有的标准库以供使用

luaL_openlibs(L);

♥ C++和Lua的数据交互

上文我们已经说到,二者通信是通过栈,接下来我们具体分析一下都需要哪些操作


♣ C++调用Lua方法传递参数

我们先写一段简单的lua代码,一句输出,一个可以将参数输出的方法print_parm

在这里插入图片描述

我们C++加载逻辑如下图,在第一个例子的基础上稍作修改,运行后成功的输出了第二张图的效果

在这里插入图片描述
在这里插入图片描述

调用Lua一共经历了下面几个步骤

  • 第一步:加载脚本,接口luaL_dofile可以供我们加载lua脚本

参数1:创建好的lua_State
参数2:Lua脚本的路径

luaL_dofile(L, "Test.lua");
  • 第二步:获取函数,接口lua_getglobal可以供我们获取已经加载好的Lua脚本内的全局字段,获取后会压入栈

参数1:创建好的lua_State
参数2:Lua中的全局变量

lua_getglobal(L, "print_parm");	
  • 第三步:参数压入栈,接口lua_pushxxx可以供我们将Lua函数需要的参数压入到栈中

参数1:创建好的lua_State
参数2:具体对应类型的参数值

lua_pushnumber(L, 10);				
lua_pushstring(L, "我真帅");		
lua_pushboolean(L, true);	

经历了上述三个步骤之后,我们的栈会变成下图的样子

在这里插入图片描述

  • 第四步:调用Lua函数,接口lua_pcall调用我们之前压入栈中的Lua函数

参数1:创建好的lua_State
参数2:函数需要的参数数量
参数3:Lua函数的返回值数量
参数4:错误处理函数,成功返回0,失败返回错误码

lua_pcall(L, 3, 0, 0);	

♣ Lua调用C++方法

这一块我们看如何在Lua内调用已经写好的方法,这一次先写C++代码,如下图所示

在这里插入图片描述

然后再写一段Lua程序,程序内调用addNum方法,将参数相加后输出,执行后入下2图显示的输出效果

在这里插入图片描述
在这里插入图片描述

其中需要重点介绍的步骤如下

  • 第一步:准备函数,我们需要预先准备一个要给Lua使用的方法,参数必须是lua_State的实例
int AddNum(lua_State *L)
{
	int n1 = lua_tonumber(L, -1);
	int n2 = lua_tonumber(L, -2);

	lua_pushnumber(L, n1+n2);
	return 1;
}
  • 第二步:注册方法,一定要在加载Lua脚本前通过接口lua_register将函数进行注册
lua_register(L, "addNum", AddNum);

参数1:创建好的lua_State
参数2:给Lua映射的方法名
参数3:注册的C++方法名

  • 第三步:在Lua中执行方法,在Lua中要使用刚才lua_register方法第二个参数映射的名字来调用方法
num = addNum(10, 15)

♠ C API一些常见函数

上文中我们已经用到了很多去操作数据交换和注册方法的函数,下面我们分类列举一些常用的接口


♥ 压入数据

我们已经了解到了C/C++和Lua的相互调用都是通过栈进行的,其中必不可少的操作就是向栈中压入数据

下面我们列举向栈中压入不同数据的方法

函数名功能
lua_pushnil压入常量nil
lua_pushboolean压入bool值
lua_pushnumber压入双精度浮点值
lua_pushinteger压入整型
lua_pushlstring压入字符串非\0结尾
lua_pushstring压入字符串\0结尾
int lua_checkstack ( lua_State *L, int sz);

注:栈中至少会有20个空闲的位置,一般情况下够用,特殊情况使用接口lua_checkstack看是否有足够空间


♥ 查询数据

我们一般以栈顶为参照,第一个元素(最后被压入栈的)索引-1,第二个索引-2,以此类推

C API提供了一系列名为lua_is*的函数用来判断栈内元素类型,下面列举了一些常见的

函数名功能
lua_isfunction是否为方法(c或lua)
lua_istable是否为lua的table
lua_isuserdata是否为lua的userdata
lua_isnil是否为nil
lua_isboolean是否为bool
lua_isthread是否为thread
lua_isnumber是否为数字
lua_isstring是否为字符串或数字

C API提供了一系列名为lua_to*的函数用来从栈中获取一个值,下面列举了一些常见的

函数名功能
lua_toboolean获取布尔值
lua_tonumber获取浮点值
lua_tothread获取thread
lua_tolstring获取字符串
lua_tointeger获取整型

注:即使对应栈获取的元素类型不正确,这些函数也不会报错,可能会返回Null


♥ 其他栈操作

除了上述在C语言和栈之间交换数据的函数外,C API还提供了下列用于通用栈操作的
函数

函数名功能
lua_gettop返回栈中元素的个数
lua_settop将栈顶设置为一个指定的值
lua_pushvalue将指定索引上的元素的副本压入栈
lua_rotate将指定索引元素向栈顶转动n个位置
lua_remove删除指定索引的元素
lua_insert将栈顶元素移动到指定位置
lua_replace弹出一个值,并将栈顶设置为指定索引上的值
lua_copy将一个索引上的值复制到另一个索引上

♠ 推送

  • Github
https://github.com/KingSun5

♠ 结语

若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。

👉 本文属于原创文章,转载请评论留言,并在转载文章头部著名作者出处👈

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

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

相关文章

云南智慧档案库综合管理系统建设解决方案

一、智慧档案管理系统建设背景 档案作为一种特殊的文献&#xff0c;是人类社会活动的产物&#xff0c;具有特殊的价值&#xff0c;其价值可以概括为现实价值和历史价值。档案是人类留给国家和社会的宝贵财富&#xff0c;它在经济与社会建设中起着重要的作用。档案是反映一个单…

多重共线性的处理方法

回归分析需要考虑多重共线性问题。多重共线性是指自变量之间存在高度相关性&#xff0c;导致回归模型的系数估计不稳定和假设检验不可靠。在实际应用中&#xff0c;许多自变量之间都可能存在一定程度的相关性&#xff0c;如果没有进行控制&#xff0c;就会导致多重共线性问题的…

设计模式之美-实战二:如何对接口鉴权这样一个功能开发做面向对象分析?

面向对象的三个环节&#xff1a;面向对象分析&#xff08;OOA&#xff09;、面向对象设计&#xff08;OOD&#xff09;、面向对象编程&#xff08;OOP&#xff09;。只知道OOA、OOD、OOP只能说有一个宏观了解&#xff0c;我们更重要的还是要知道“如何做”&#xff0c;也就是&a…

【快应用】多语言适配案例

【关键词】 多语言&#xff0c;$t 【问题背景】 快应用平台的能力会覆盖多个国家地区&#xff0c;平台支持多语言的能力后&#xff0c;可以让一个快应同时支持多个语言版本的切换&#xff0c;开发者无需开发多个不同语言的源码项目&#xff0c;避免给项目维护带来困难。使用系…

子串分值--子串分值和 模拟,找规律

子串分值和 n有十万&#xff0c;需要找规律&#xff0c;O(n^2)不满足要求 分析样例&#xff1a; Ababc 01234 长度是n5 索引下标-对应字符 0A贡献 112 a;ab;---22*1 next a 2&#xff1b; pre a -1 1b贡献 112 b;ba;---42*2 next b 3&#xff1b; pre b -1 2a贡献 1113…

2023年测试前景?测试开发工程师养成记,开发企业级测试平台...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 测试开发&#xff…

IDS 和 IPS 日志监控

什么是IDS/IPS 入侵检测系统 &#xff08;IDS&#xff09; 和入侵防御系统 &#xff08;IPS&#xff09; 是监视组织网络中的流量以检测和防止恶意活动和策略违规的网络组件。 入侵检测系统&#xff08;IDS&#xff09;和入侵防御系统&#xff08;IPS&#xff09;可以说是企业…

C语言学习分享(第八次)------数据的存储

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C语言学习分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C语言知识   &#x1f51d;&#x1f51d; 数据的存储 1. 前言&#x1f6a9;2…

现代化智慧档案室建设图文推介

1、防火。建立档案库房防火制度&#xff0c;档案库房附近严禁存放易燃、易爆物品&#xff0c;库房内严禁吸烟&#xff0c;并备有灭火器&#xff0c;经常进行检查更换。 主要设备为&#xff1a;烟雾探测器和感温探测器和七氟丙烷灭火系统。 2、防潮。库房内备有温湿度计&#x…

GB28181 对接海康平台,解决音视频卡顿问题

GB28181 对接海康平台,解决音视频卡顿问题 一、概述二、问题分析1、设备对比分析2、抓包对比分析3、验证分析结果三、总结四、讨论一、概述 设备使用GB28181协议对接海康平台时,发现音频和视频存在卡顿现象,不是一直卡顿,有时候卡有时候不卡,但是卡顿的时候音视频一起卡顿…

炫技操作--递归实现翻转链表(java)

递归实现链表的逆序 leetcode 206题。 翻转链表递归解法普通方式实现链表翻转链表专题 leetcode 206题。 翻转链表 leetcode链接用于测试 题目&#xff1a;描述 将一个链表翻转&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 递归解法 解题思路…

chatgpt赋能python:Python中删除的SEO

Python中删除的SEO Python是一个强大的编程语言&#xff0c;它广泛应用于各种领域&#xff0c;包括SEO。在SEO领域中&#xff0c;Python可以用来处理各种数据&#xff0c;包括删除不必要的数据。本文将介绍如何在Python中删除SEO数据。 什么是SEO数据&#xff1f; SEO是搜索…

代码创造的欢乐世界-通用人工智能让儿童熟练应用编程

想要复杂的参考这一篇&#xff0c;使用云平台即可完成&#xff1a; 美美的圣诞树画出来-CoCube- 把圣诞树换成六一儿童节主题的就可以啦。 这一篇是使用chatgpt类应用&#xff0c;给出关键提示词&#xff0c;代码自动生成哦。 神十六发射成功&#xff0c;科技工作者博士学位…

python接口自动化使用requests库发送http请求

目录 前言一、requests库二、HTTP 请求方法三、发送GET请求四、发送POST请求五、获取响应数据六、高级操作 6.1文件下载6.2文件上传6.3SSL证书验证6.4保持会话6.5requests封装总结 前言 今天笔者想和大家来聊聊python接口自动化如何使用requests库发送http请求&#xff0c;废…

【JavaSE】Java基础语法(三十七):Java 中的 String 类(源码级别)

文章目录 1. 构造方法1.1 String()1.2 String(String original)1.3 String(char[] chars)1.4 String(char数组,起始下标,长度)1.5 String(byte数组)1.6 String(byte数组,起始下标,长度)1.7 String(StringBuffer buffer)1.8 String(StringBuilder builder) 2. 普通方法2.1 char …

【Python教学】Python兼职有哪些?给你们分享一下最适合学生党/工作党的Python兼职攻略以及接私活经验

文章目录 前言一、做兼职的优势二、兼职种类三、基本技能要求四、平台和渠道五、案例分析六、做兼职注意事项总结 前言 Python是一种高级编程语言&#xff0c;它具有简单易学、代码可读性高、功能强大等特点&#xff0c;被广泛应用于数据分析、人工智能、Web开发等领域。Pytho…

修改mysql密码与mac中mysql的启动与终止

目录 修改mysql密码 1.进入你的mysql文件下的bin目录下&#xff1a; 2.修改mysql密码 mysql的启动与终止&#xff08;mac&#xff09; 修改mysql密码 1.进入你的mysql文件下的bin目录下&#xff1a; 如果不知道自己电脑上的mysql在哪里的话&#xff0c;输入&#xff1a; …

Redis7实战加面试题-高阶篇(布隆过滤器BloomFilter,缓存预热+缓存雪崩+缓存击穿+缓存穿透)

布隆过滤器BloomFilter 先看看大厂真实需求面试题反馈 1.现有50亿个电话号码&#xff0c;现有10万个电话号码&#xff0c;如何要快速准确的判断这些电话号码是否已经存在? 2.判断是否存在&#xff0c;布隆过滤器了解过吗? 3.安全连接网址&#xff0c;全球数10亿的网址判断 …

Java 多线程共享数据引发的问题

一、多线程并发情况下&#xff0c;线程不安全​​ 1、使用多线程实现银行取钱​​ package theads;/*** ClassName: TestBank* Description: TODO* Author: HLX* date: 2023/5/29 14:53* Version: V1.0*//*** 线程不安全&#xff1a; 取钱* <p>* 逻辑&#xff1a;* 连取…

更改测试用例执行顺序的几种自动化方法

前言 在自动化测试中&#xff0c;自动化测试用例设计原则就是执行过程时不能存在依赖顺序&#xff0c;那么如果测试用例需要按照指定顺序执行&#xff0c;这个时候应该怎么做呢&#xff1f;目前单元测试框架中unittest没有办法改变测试用例的执行顺序&#xff0c;但是另一个单…