在C函数中保存状态:registry、reference和upvalues

  C函数可以通过堆栈来和Lua交换数据,但有时候C函数需要在函数体的作用域之外保存某些Lua数据,那么我们想到全局变量或static变量,这样做的缺点是:

  1. 为Lua设计C函数库时,导致不可重入;
  2. 不是所有的Lua值都能很好的保存到C变量中。那么可不可以将值保存在Lua全局变量里面呢,可以,Lua就提供了一个独立的被称为registry的表,但是Lua代码本身不能访问它。
  • registry全局注册表

解释:一个普通的Lua表,使用假索引(pseudo-index)LUA_REGISTRYINDEX访问。C代码可以访问,Lua代码不能访问。

用途:解决C函数保留全局Lua值的问题。

注意:所有的C库共享相同的registry,所以对于key的命名需要具有全局唯一性。

1  // 获取registry表键值"KEY"对应的值的方法:
2  lua_pushstring(L, "KEY");
3  lua_gettable(L, LUA_REGISTRYINDEX);
  • reference引用系统

解释:通过一个整数来唯一标识一个Lua数据对象,由两个函数luaL_ref和luaL_unref组成,这对函数用来不需要担心名称冲突的将值保存到registry中去。

用途:将一个指向Lua值的reference存储到一个C结构体中,这个reference是一个int的KEY。

注意:栈顶值为nil的时候,不会产生reference,luaL_ref函数会返回LUA_REFNIL,而对LUA_REFNIL解引用是没有效果的。

重要函数:

int luaL_ref (lua_State *L, int t);

创建并返回一个引用reference,并将[reference,栈顶值v]加入t对应的表中。

void luaL_unref (lua_State *L, int t, int ref);

解引用,将t对应的表中的[reference,v]键值对删除。

1 // 对栈顶的值v生成一个引用,即将[r, v]存到LUA_REGISTRYINDEX表中
2 int r = luaL_ref(L, LUA_REGISTRYINDEX);
3 // 将一个引用值入栈
4 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
5 // 解引用,即释放reference和值
6 luaL_unref(L, LUA_REGISTRYINDEX, r);
  • upvalues机制

解释:当创建一个C函数时可以关联一些值,这样就创建了一个C闭包,这些关联值就叫做upvalues。

用途:实现了与C static变量等价的概念,这种变量只能在特定的函数内可见。

使用:通过lua_upvalueindex(n)生成假索引来访问。    

 1 // 预声明
 2 static int counter (lua_State *L);
 3 // 创建C闭包的工厂函数
 4 int newCounter (lua_State *L)
 5 {
 6     lua_pushnumber(L, 0);
 7     lua_pushcclosure(L, &counter, 1);
 8     return 1;
 9 }
10 // C函数
11 static int counter (lua_State *L)
12 {
13     double val = lua_tonumber(L, lua_upvalueindex(1));
14     lua_pushnumber(L, ++val);   /* new value */
15     lua_pushvalue(L, -1);       /* duplicate it */
16     lua_replace(L, lua_upvalueindex(1));  /* update upvalue */
17     return 1;  /* return new value */
18 }

注意:永远不要使用数字作为registry 的key,因为这种类型的key是保留给reference系统使用。

假索引(pseudo-index)的特点:

  1. 对应的值不在栈中;
  2. 使用方式类似于栈索引,大多数接受索引为参数的函数都能使用;
  3. 那些操作栈本身的函数不能使用假索引,比如lua_remove,lua_insert等。

与Lua闭包(在Lua代码中,一个闭包是一个从外部函数访问局部变量的函数)不同的是,C闭包不能共享upvalues:每一个闭包都有自己独立的变量集。然而,我们可以设置不同函数的upvalues指向同一个表,这样这个表就变成了一个所有函数共享数据的地方。

时间: 2024-12-29 13:47:25

在C函数中保存状态:registry、reference和upvalues的相关文章

在C 函数中保存状态:registry、reference和upvalues

在C函数中保存状态:registry.reference和upvalues C函数能够通过堆栈来和Lua交换数据,但有时候C函数须要在函数体的作用域之外保存某些Lua数据.那么我们想到全局变量或static变量,这样做的缺点是:(1)为Lua设计C函数库时,导致不可重入.(2)不是全部的Lua值都能非常好的保存到C变量中.那么可不能够将值保存在Lua全局变量里面呢,能够,Lua就提供了一个独立的被称为registry的表,可是Lua代码本身不能訪问它. 1.registry全局注冊表 解释:一个

[Lua]在C函数中保存状态--注册表,环境表,upvalue

什么叫做在C函数中保存状态?比如你现在使用Lua调用了C函数Func1,但是Func1中有一些数据在调用完以后保存下来,供以后使用.而这些数据就是所谓的状态,也就是我们需要保存的东东.有人就会说了,Lua调用C时,把所有的需要保存的状态都返回到Lua中,当调用下一个函数时,将需要的状态当做参数再传进去,不错,是一个办法,但是很麻烦.方法一:注册表:方法二:环境:方法三:upvalue. 注册表是一个全局的table,它只能被C代码访问.通常,可以用它来保存那种需要在几个模块中共享的数据: 但是,

在C函数中保存状体:registry、reference和upvalues

C函数可以通过堆栈来和Lua交换数据,但有时候C函数需要在函数体的作用域之外保存某些Lua数据,那么我们想到全局变量或static变量,这样做的缺点是:(1)为Lua设计C函数库时,导致不可重入:(2)不是所有的Lua值都能很好的保存到C变量中.那么可不可以将值保存在Lua全局变量里面呢,可以,Lua就提供了一个独立的被称为registry的表,但是Lua代码本身不能访问它. 1.registry全局注册表 解释:一个普通的Lua表,使用假索引(pseudo-index)LUA_REGISTRY

程序中保存状态的方式之Cookies

程序中保存状态的方式之 Cookies,之前写过一篇关于ViewState的.现在继续总结Cookies方式的 新建的测试页面login <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML

程序中保存状态的方式之ViewState

程序中保存状态的方式有以下几种: 1.Application 2.Cookie 3.Session 4.ViewState:ViewState是保存状态的方式之一,ViewState实际就是一个Hidden字段,但是它是服务器控件状态保存的基础如下代码 1 <form method="post" action="./pay.aspx" id="form1"> 2 <div class="aspNetHidden&quo

在c中保存状态

1. 注册表 注册表是一个普通的table,我们可以将c函数中需要保存的状态都存储在注册表中,注册表是可以被多个c模块共享的. 由于注册表是一个普通table,我们同样可以在栈中对其进行操作,只是这个table的索引是由一个常量LUA_REGISTRYINDEX进行索引. 如何向注册表中存入一个值对: lua_pushstring(L, "hello"); lua_setfield(L, LUA_REGISTRYINDEX, "key"); lua_getfield

Spring MVC不要在@Service bean中保存状态

先看这么一段代码: @Service public class AccountService { private String message; public void foo1() { if (true) { this.message = "a"; } else { this.message = "b"; } } public void foo2() { // 修改this.message的代码... // ... ... } } 如果你打算在@Controlle

如何实现 React 中的状态自动保存?

什么是状态保存? 假设有下述场景: 移动端中,用户访问了一个列表页,上拉浏览列表页的过程中,随着滚动高度逐渐增加,数据也将采用触底分页加载的形式逐步增加,列表页浏览到某个位置,用户看到了感兴趣的项目,点击查看其详情,进入详情页,从详情页退回列表页时,需要停留在离开列表页时的浏览位置上 类似的数据或场景还有已填写但未提交的表单.管理系统中可切换和可关闭的功能标签等,这类数据随着用户交互逐渐变化或增长,这里理解为状态,在交互过程中,因为某些原因需要临时离开交互场景,则需要对状态进行保存 在 Reac

面试中被问到:Android中activity保存状态数据到底该在哪个方法中进行

今天接到一个电面,途中面试官问到一个问题,如果一个activity在后台的时候,因为内存不足可能被杀死,在这之前如果想保存其中的状态数据,比如说客户填的一些信息之类的,该在哪个方法中进行. 我听到的第一反应就是说:在onPause方法中进行保存状态的操作.但是面试官说:onPause()的持续时间很短,假如要进行一些长时间的操作呢? 然后我就纠结了,因为我知道,如果是因为内存不足而被清理,onDestroy()方法一般是不会被执行的.所以只好实话实说,只知道onDestroy在这种情况下不一定会