Lua 与C 交互之LUA_REGISTRYINDEX(3)
通常来说,C函数需要保留一些非局部的数据,也就是指那些超过他们作用范围的数据。C语言中我们使用全局变量或者static变量来满足这种需要。然而当你为Lua设计一个程序库的时候,全局变量和static变量不是一个好的方法。首先,不能将所有的Lua值保存到一个C变量中。第二,使用这种变量的库不能在多个Lua状态的情况下使用。
一个替代的解决方案是将这些值保存到一个Lua全局变两种,这种方法解决了前面的两个问题。Lua全局变量可以存放任何类型的Lua值,并且每一个独立的状态都有他自己独立的全局变量集。然而,并不是在所有情况下,这种方法都是令人满意地解决方案,因为Lua代码可能会修改这些全局变量,危及C数据的完整性。为了避免这个问题,Lua提供了一个独立的被称为registry的表,C代码可以自由使用,但Lua代码不能访问他。
假索引
LUA_REGISTRYINDEX、LUA_ENVIRONINDEX、 LUA_GLOBALSINDEX是一个假索引(pseudo-indices),一个假索引除了他对应的值不在栈中之外,其他都类似于栈中的索引。 Lua API 中大部分接受索引作为参数的函数,其实可以理解为一张普通表格,你可以使用任何非nil的Lua值来访问她的元素。
The Registry
Lua 提供一个独立的被称为 registry 的表, C 可以自由使用,但 Lua 代码不能访问他。索引:LUA_REGISTRYINDEX,官方解释:
Lua provides a registry, a pre-defined table that can be used by any C code to store whatever Lua value it needs to store. This table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table, but it should take care to choose keys different from those used by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name or a light userdata with the address of a C object in your code
注意的地方:Key值,你可以使用字符串或者C函数的指针以light userdata作为键值。
/* variable with an unique address */
static const char Key = 'k';
/* store a number */
lua_pushlightuserdata(L, (void *)&Key); /* push address */
lua_pushnumber(L, myNumber); /* push value */
/* registry[&Key] = myNumber */
lua_settable(L, LUA_REGISTRYINDEX);
/* retrieve a number */
lua_pushlightuserdata(L, (void *)&Key); /* push address */
lua_gettable(L, LUA_REGISTRYINDEX); /* retrieve value */
myNumber = lua_tonumber(L, -1); /* convert to number */
References
为了解决Key唯一的问题,引入 References:Reference 系统是由辅助库中的一对函数组成,这对函数用来不需要担心名称冲突的将值保存到 registry 中去。
int luaL_ref (lua_State *L, int t);
lua_rawgeti(L, LUA_REGISTRYINDEX, r);
void luaL_unref (lua_State *L, int t, int ref);
luaL_ref Creates and returns a reference, in the table at index t, for the object at the top of the stack (and pops the object). A reference is a unique integer key. As long as you do not manually add integer keys into table t, luaL_ref ensures the uniqueness of the key it returns. You can retrieve an object referred by reference r by calling lua_rawgeti(L, t, r).
If the object at the top of the stack is nil, luaL_ref returns the constant LUA_REFNIL. The constant LUA_NOREF is guaranteed to be different from any reference returned by luaL_ref.
luaL_unref frees a reference and its associated object.
一些相关的优化技巧:
http://blog.codingnow.com/2006/11/lua_c.html “Lua 中写 C 扩展库时用到的一些技巧”
http://blog.codingnow.com/2006/01/_lua.html “Lua中字符串使用优化”
一些问题(待补充)
为什么lua要提供这个区间?有这些变量保存在C或者宿主语言中不是也挺好的吗?
可以理解的是:
- 分散在宿主语言不同部分的Lua交互代码可以很方面的获取全局信息
- 上面提到的,ref速度问题。
但是看了几个实现交互库,都是这样来处理的,其根本的原因是什么呢?
Lua 与C 交互之LUA_REGISTRYINDEX(3)的更多相关文章
- Lua和C++交互 学习记录之九:在Lua中以面向对象的方式使用C++注册的类
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 在 ...
- Lua和C++交互 学习记录之二:栈操作
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...
- Lua和C++交互详细总结
转自:http://cn.cocos2d-x.org/tutorial/show?id=1474 一.Lua堆栈 要理解Lua和C++交互,首先要理解Lua堆栈. 简单来说,Lua和C/C++语言通信 ...
- Lua与C++交互初探之Lua调用C++
Lua与C++交互初探之Lua调用C++ 上一篇我们已经成功将Lua的运行环境搭建了起来,也成功在C++里调用了Lua函数.今天我来讲解一下如何在Lua里调用C++函数. Lua作为一个轻量级脚本语言 ...
- Lua 和 C 交互中虚拟栈的操作
Lua 和 C 交互中虚拟栈的操作 /* int lua_pcall(lua_State *L, int nargs, int nresults, int msgh) * 以保护模式调用具有" ...
- 用好lua+unity,让性能飞起来——lua与c#交互篇
前言 在看了uwa之前发布的<Unity项目常见Lua解决方案性能比较>,决定动手写一篇关于lua+unity方案的性能优化文. 整合lua是目前最强大的unity热更新方案,毕竟这是唯一 ...
- Lua和C++交互 学习记录之八:C++类注册为Lua模块
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...
- Lua和C++交互 学习记录之七:C++全局函数注册为Lua模块
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...
- Lua和C++交互 学习记录之六:全局函数交互
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...
随机推荐
- leetcode — palindrome-number
import org.lep.leetcode.parseint.IntegerParser; /** * Source : https://oj.leetcode.com/problems/pali ...
- ida 调试 android fork
在使用ida 调试android native代码时经常会碰见fork子进程的情况出现,而运行一个 android_server只能对一个进程进行调试或者attach,而ida 默认端口是23946, ...
- [译]初试C# 8.0
原文地址: https://blogs.msdn.microsoft.com/dotnet/2018/12/05/take-c-8-0-for-a-spin/ 初试C# 8.0 昨天我们宣布了Visu ...
- 检测到是移动端还是PC端进入页面,加载不同样式表现
if(/AppleWebKit.*mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alc ...
- CTE(公用表表达式)
-> 将复杂的派生表写在中间from子句中变得十分臃肿,给为维护等操作带来麻烦 -> 将这个派生表要是能提前到前面,给一个别名,后面查询的时候直接使用别名即可语法: with 表的别名 a ...
- VB.NET datagridview的操作
'空值判斷 If IsDBNull(DataGridView1.Item(1, 1).Value) = True Then DataGridView1.Item(1, 1).Value = " ...
- 安装Java语言的jdk,配置java环境变量
一.windows 安装jdk win7 下载jdk: 地址 https://www.oracle.com/technetwork/java/javase/downloads/index.html ...
- Perfect hashing (And Minimal perfect hashing)
Perfect Hashing: A hash function that is injective-that is, maps each valid input to a different has ...
- Hybris IMPEX.
1.Impex是基于java Model的一种面向对象的数据操作手段,因此写impex代码前需要理清java Model之间的依赖关系. 2.基本语法:mode type[modifier=val ...
- 初识scss:配置与运行
1.SCSS和Sass Sass 和 SCSS 其实是同一种东西,我们平时都称之为 Sass.他们都是用Ruby开发Css预处理器,boostrap4已经将less换成了sass. 不同之处: 文件拓 ...