C 函数中如何保存 Lua 的数据(2)

简介: C 函数中如何保存 Lua 的数据(2)

二、上值

每一次在 Lua 中创建新的 C 函数时,可以将任意数量的上值和这个函数相关联,而每个上值都可以保存一个 Lua 值。后面调用该函数时,可以通过伪索引自由的访问这些上值。这种 C 函数与其上值的关联称为闭包。

 

上值的个数有限制, C 语言函数中最多可以有 255 个上值,lua_upvalueindex 的最大索引值是 256 。

1、如何为闭包添加上值

这里结合一个例子讲解,我们创建一个 C++ 函数给 Lua 调用,这个 C++ 函数是一个累加的闭包,每次调用都会产生新的值,而且每个闭包的值互不影响。

第一步,创建累加的 C 函数。

 

函数 newCounter:创建闭包的函数,每次 Lua 中调用 newCounter 函数,都会返回一个新的闭包,会携带新的上值。

函数 counter :真正的执行函数,每次 Lua 执行 newCounter 创建后的闭包都会运行该函数,该函数会 “更新上值以便下次使用” 和 “返回更新后的上值”。

image.png

第二步:将上述函数以库的形式添加到 Lua 中

image.png

image.png

第三步:编写 Lua 文件,并运行

Lua 中创建两个累加器,a 累加器累加三次,b 累加器只累加一次,可以从运行结果看出,两个累加器互不影响。

image.png

运行代码

image.png

运行结果

image.png

2、lua_pushcclosure

image.png

描述:

将一个 C 函数作为闭包压入 Lua 栈中。

参数:

· 参数 L: Lua 状态机指针。

· 参数 fn: 一个 C 函数指针,表示要作为闭包压入 Lua 栈的函数。

· 参数 n: 一个整数,表示闭包所使用的上值数量。

3、lua_upvalueindex

image.png


描述:

他是一个宏,用于获取闭包的上值在 Lua 栈中的索引。这个索引是一个伪索引,他和其他的栈索引一样,唯一的区别在于它不存在于栈中。

参数:

 

参数 i : 表示要获取的上值的索引,第一个上值的索引为 1 。

返回值:

 

返回值是一个整数,表示该上值在 Lua 栈中的索引。

 

如果传入的索引超出了范围,则会返回 LUA_TNONE 。可以使用 lua_isnone 函数进行判断上值的伪索引是否合法,例如下面代码:

image.png

三、共享上值

在封装一个库给 Lua 进行调用的时候,有时需要库函数间共享一些数值或变量。虽然注册表也可以达到这一目的,但不够优雅,毕竟将库的过多细节暴露,并且存在 key 被覆盖的风险,所以更好的做法应该是使用上值。

 

Lua 为这种场景提供了一种解决方案,简化在库函数间共享上值的做法。

 

之前我们创建一个 Lua 库时,一般都使用 luaL_newlib 函数,他其实是个宏,具体实现如下所示。

image.png

要达到共享上值的关键点在于 luaL_setfuncs 的三个参数,用 luaL_newlib 创建库,默认情况下传递的都是 0 ,即没有共享上值,所以我们只需要改造下就可以支持了。

定义一个库,这个库中有两个函数,共享三个上值,分别为整数型、字符串、table,两个函数均可对共享上值获取和修改

 

第一步,定义库函数和设置库的共享上值。

 

showInfo 和 showCode 是两个库函数,会获取各自的参数和共享上值,进行操作后返回给 Lua

 

共享上值的关键点在 luaopen_user 函数,函数中会压入三个值,然后调用 luaL_setfuncs 将这三个值作为库的共享上值。

image.png

image.png

image.png

第二步,编写 lua 文件。

只是简单的调用库函数,然后打印返回值。

image.png

第三步,将库函数添加到 Lua 中,并运行 Lua 文件。 image.png

运行结果如下。

image.png


四、注册表和上值的区别

注册表提供了全局变量的概念,只要获取到相同的 lua_State ,就能通过 lua_State 访问到相同的注册表,通过对应的 key 获取需要的 value 。

上值则实现了一种只能在特定的函数中可见的机制,相较于注册表能做到更小粒度的共享值。

五、写在最后

Lua 项目地址:Github传送门 (如果对你有所帮助或喜欢的话,赏个star吧,码字不易,请多多支持)

如果觉得本篇博文对你有所启发或是解决了困惑,点个赞或关注我呀

公众号搜索 “江澎涌”,更多优质文章会第一时间分享与你。

 

目录
相关文章
|
6月前
lua字符串与十六进制数据转换
lua字符串与十六进制数据转换
175 2
|
6月前
|
存储 C语言 图形学
C 函数中如何保存 Lua 的数据(1)
C 函数中如何保存 Lua 的数据(1)
87 0
|
存储 Java C语言
lua变量、数据类型、if判断条件和数据结构table以及【lua 函数】
lua变量、数据类型、if判断条件和数据结构table以及【lua 函数】
91 0
|
1月前
lua面向对象(类)和lua协同线程与协同函数、Lua文件I/O
Lua的面向对象编程、协同线程与协同函数的概念和使用,以及Lua文件I/O操作的基本方法。
27 4
lua面向对象(类)和lua协同线程与协同函数、Lua文件I/O
|
1月前
|
数据可视化 开发者 索引
详解Wireshark LUA插件函数:function p_myproto.dissector(buffer, pinfo, tree)
在 Wireshark 中,LUA 插件通过 `function p_myproto.dissector(buffer, pinfo, tree)` 扩展协议解析能力,解析自定义应用层协议。参数 `buffer` 是 `PacketBuffer` 类型,表示原始数据包内容;`pinfo` 是 `ProtoInfo` 类型,包含数据包元信息(如 IP 地址、协议类型等);`tree` 是
52 1
|
消息中间件 存储 NoSQL
【实战】使用Lua脚本怎么清理redis中的数据【实战】使用Lua脚本怎么清理redis中的数据
首先我们通过hiredis 向redis 中写入了数据,这里我们主要以测试为目的,所以,Key 值设定为毫秒级时间戳。
131 0
[✔️]lua中的module函数
[✔️]lua中的module函数
205 0
|
C语言 索引
lua语言——函数
lua语言——函数
153 0
|
1月前
|
缓存 分布式计算 NoSQL
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
25 2