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

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

在前面的文章中,C 函数操作的数据的生命周期都是在该函数执行期间。有时我们需要保存一些非局部数据,虽然在 C 语言中,我们可以使用全局变量或静态变量来满足非局部变量的持有,但是当我们需要使用 Lua 编写库函数时,就会遇到一些问题:

1. C 语言中无法保存普通的 Lua 值。

2. 如果 Lua 库函数中使用了全局变量或静态变量来保存一些数据,会导致该库在多个 lua_State 中使用受到约束。(因为每个 lua_State 间是相互独立的,而 C 函数中使用的全局变量和静态变量却是共用的,这里会出现数据混乱问题。)

因此 Lua 提供了 C-API ,让 C 语言函数有两个地方可以存储非局部数据:

1. 注册表

2. 上值

经过前面文章的学习,可以知道 Lua 内部存储 “非局部数据” ,则通过 “全局变量” 和 “非局部变量” 。

一、注册表

注册表是一张能被 C 代码访问的全局表。 注册表总是位于伪索引 LUA_REGISTRYINDEX 中。

 

Lua 中接收索引作为参数的 C-API 都可以接收这个伪索引 LUA_REGISTRYINDEX 。只是有一些需要除外,即对栈操作的 C-API 则不可以,例如:lua_remove 、lua_insert 等。

1、如何操作注册表

对注册表的操作,可以认为是对普通表 table 操作。

 

可以使用对 table 设置或获取 value 操作的 C-API。

和 table 的约束一样,不能用 nil 作为 key。但注册表更为严格,不能使用数值类型作为 key ,因为 Lua 将数值类型作为引用系统的保留字。

因为注册表是全局使用的一个 table ,不同模块均可以使用他,所以在 “注册表” 中使用一个独一无二的 key 较为关键,这样才不会被其他模块覆盖,导致数据问题。

有几种方式可以实现键的不同:

模块内使用的 key 值,均增加模块名作为前缀。例如一个 “3D-Graphics” 的模块,可以将他的 key 取为 “3D-Graphics-xxx” 。

使用引用系统辅助库为我们生成唯一 key ,这个 key 则为整数类型,这就是上面讲到不能自行创建数值类型 key 的原因。

使用 C 代码中静态变量的地址,这样也可以达到全局的唯一。

下面遍一一举例子进行分享

2、模块中使用自定义 key 值

假设我们要编写一个 “3D 渲染” 相关的库,将它命名为 “3D-Graphics” 。在这个模块中,按照约定所有存入注册表中的自定义 key 值都需要带上 “3D-Graphics-” 前缀。

image.png

假设我们需要将值存入到 key 为 “xxx” ,则在注册表的名为 “3D-Graphics-xxx” ,下面便是展示如何将值存入到注册表中。

image.png

可以发现,其实对注册表的操作和对 table 的操作并没有太大的区别,只是将索引替换为注册表的伪索引即可。

最后输出为:

image.png

3、使用引用系统生成索引

为了避免冲突,Lua 提供了一套引用系统,为此 Lua 引入了两个 C-API 函数。

image.png

举个例子

1. 向注册表的申请一个索引同时存入值,然后获取该值,最后释放。

2. 再次申请,会发现会分配同一个 key 值。

image.png

运行后输出内容如下:

image.png

值得注意

1. 如果将 nil 作为值调用 luaL_ref 都不会创建新的引用,都会返回一个常量引用 LUA_REFNIL

image.png

2.如果将 LUA_REFNIL 进行释放不会有什么作用,例如下面的代码不会有任何作用。

image.png

3.如使用 LUA_REFNIL 进行获取注册表的值,会导致压入一个 nil 值到栈中。

image.png

4.引用系统定义了一个 LUA_NOREF ,表示无效的引用。

image.png

5. 创建 lua 状态时,注册表中有两个预定义的引用:

image.png

通过以下代码可以更加具体的感受到。

image.png

输出内容如下

image.png

4、使用 C 语言静态变量做唯一 key

这种方法也可以实现在注册表中创建唯一的 key 。只是这种方式需要借助 lua_pushlightuserdata 函数将一个 C 语言指针压入到栈中。

以下的代码进行展示如何使用。

image.png

可以看到,将通过 lua_pushlightuserdata 将静态变量指针压入栈作为 key ,然后设置 value ,最后对注册表的设置、获取操作和普通表的操作是一样的。

输出如下所示。

image.png

Lua 为了简化这种操作,提供了两个 C-API :

image.png

参数 p 是需要压入的静态变量指针,上面代码的操作就可以减少一步,具体代码如下,运行后的效果是一致的

image.png

值得一提

注册表没有元表lua_rawsetplua_rawgetp 都是原始访问,效率会比普通访问快一些。

 

 

目录
相关文章
|
7月前
lua字符串与十六进制数据转换
lua字符串与十六进制数据转换
208 2
|
存储 Java C语言
lua变量、数据类型、if判断条件和数据结构table以及【lua 函数】
lua变量、数据类型、if判断条件和数据结构table以及【lua 函数】
105 0
|
2月前
lua面向对象(类)和lua协同线程与协同函数、Lua文件I/O
Lua的面向对象编程、协同线程与协同函数的概念和使用,以及Lua文件I/O操作的基本方法。
32 4
lua面向对象(类)和lua协同线程与协同函数、Lua文件I/O
|
2月前
|
数据可视化 开发者 索引
详解Wireshark LUA插件函数:function p_myproto.dissector(buffer, pinfo, tree)
在 Wireshark 中,LUA 插件通过 `function p_myproto.dissector(buffer, pinfo, tree)` 扩展协议解析能力,解析自定义应用层协议。参数 `buffer` 是 `PacketBuffer` 类型,表示原始数据包内容;`pinfo` 是 `ProtoInfo` 类型,包含数据包元信息(如 IP 地址、协议类型等);`tree` 是
84 1
|
7月前
|
C语言 C++ 索引
C 函数中如何保存 Lua 的数据(2)
C 函数中如何保存 Lua 的数据(2)
83 1
|
消息中间件 存储 NoSQL
【实战】使用Lua脚本怎么清理redis中的数据【实战】使用Lua脚本怎么清理redis中的数据
首先我们通过hiredis 向redis 中写入了数据,这里我们主要以测试为目的,所以,Key 值设定为毫秒级时间戳。
146 0
[✔️]lua中的module函数
[✔️]lua中的module函数
223 0
|
C语言 索引
lua语言——函数
lua语言——函数
158 0
|
6天前
|
监控 安全
公司用什么软件监控电脑:Lua 脚本在监控软件扩展功能的应用
在企业环境中,电脑监控软件对保障信息安全、提升效率至关重要。Lua 脚本在此类软件中用于扩展功能,如收集系统信息、监控软件使用时长及文件操作,向指定服务器发送数据,支持企业管理和运营。
21 6