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 都是原始访问,效率会比普通访问快一些。

 

 

目录
相关文章
|
6月前
|
存储 Java C语言
lua变量、数据类型、if判断条件和数据结构table以及【lua 函数】
lua变量、数据类型、if判断条件和数据结构table以及【lua 函数】
50 0
Lua 函数
Lua函数是主要的抽象机制,用于执行任务或计算值。函数定义格式包括可选的函数作用域(默认全局)、函数名、参数列表和函数体。例如,定义一个名为`max`的函数,接收两个参数`num1`和`num2`,返回它们中的最大值。函数可以作为参数传递,如示例中将`myprint`函数传递给`add`函数,实现功能组合。
|
6天前
|
C语言
Lua 函数
Lua中的函数支持可变参数,以三点(...)表示。函数既可完成任务,也可用于计算并返回值。例如,`add(...)`函数接受任意数量参数并返回它们的和。要处理可变参数,可以将其赋值给一个表,如`arg={...}`。计算平均值的`average(...)`函数展示了如何遍历和使用这些参数。通过`select("#",...)`可以获取参数数量,`select(n, ...)`则用于访问特定位置的参数。函数定义如`function fwrite(fmt, ...)`允许固定参数与可变参数结合使用。
|
6天前
|
C语言
Lua 函数
Lua中的函数支持可变参数,用三点`...`表示。函数可以用于执行任务或返回计算值。示例中展示了如何处理可变参数,如计算参数总和(`add`函数)和平均值(`average`函数)。`select("#",...)`用于获取参数数量,`select(n, ...)`用于获取从n开始的参数列表。`average`函数在不同实例中展示了使用可变参数的方式,始终返回参数的平均值。`fwrite`函数展示了固定参数与可变参数的组合使用。
|
6天前
|
C语言 C++ 索引
C 函数中如何保存 Lua 的数据(2)
C 函数中如何保存 Lua 的数据(2)
28 1
|
6月前
|
消息中间件 存储 NoSQL
【实战】使用Lua脚本怎么清理redis中的数据【实战】使用Lua脚本怎么清理redis中的数据
首先我们通过hiredis 向redis 中写入了数据,这里我们主要以测试为目的,所以,Key 值设定为毫秒级时间戳。
64 0
|
12月前
[✔️]lua中的module函数
[✔️]lua中的module函数
116 0
|
C语言 索引
lua语言——函数
lua语言——函数
121 0
|
6天前
|
存储 NoSQL Redis
Redis的Lua脚本有什么作用?
Redis Lua脚本用于减少网络开销、实现原子操作及扩展指令集。它能合并操作降低网络延迟,保证原子性,替代不支持回滚的事务。通过脚本,代码复用率提高,且可自定义指令,如实现分布式锁,增强Redis功能和灵活性。
47 1