lua中的table、stack和registery
ok,前面准备给一个dll写wrapper,写了篇日志,看似写的比较明白了,但是其实有很多米有弄明白的。比如PIL中使用的element,key,tname,field这些,还是比较容易混淆的。今天正好搞搞清楚。
1、stack
这个应该不用多讲了,C和lua中的交互就是基于一个stack的,而且每次lua调用一个c函数,都是给分配一个新的stack。它的原型:
typedef int (*lua_CFunction) (lua_State *L);
stack中的基本单元在PIL中多成为element。
2、table
我们可以在C中定义一个struct如下:
struct ColorTable {
char *name;
unsigned char red, green, blue;
} colortable[] = {
{"WHITE", MAX_COLOR, MAX_COLOR, MAX_COLOR},
{"RED", MAX_COLOR, , },
{"GREEN", , MAX_COLOR, },
{"BLUE", , , MAX_COLOR},
{"BLACK", , , },
...
{NULL, , , } /* sentinel */
};
在C中,我们事实上可以把如上的struct当做类似下面lua代码来用:
WHITE = {r=, g=, b=}
RED = {r=, g=, b=}
...
How?我们先定义一个自己的setfield,用来往在堆顶的table中添加member“name=value”:
#define MAX_COLOR 255 /* assume that table is at the top */
void setfield (const char *name, int value) {
lua_pushstring(L, name);
lua_pushnumber(L, (double)value/MAX_COLOR);
lua_settable(L, -);
}
然后,我们创建某个颜色的table:
void setcolor (struct ColorTable *ct) {
lua_newtable(L); /* creates a table */
setfield("r", ct->red); /* table.r = ct->r */
setfield("g", ct->green); /* table.g = ct->g */
setfield("b", ct->blue); /* table.b = ct->b */
lua_setglobal(L, ct->name); /* `name' = table */
}
利用上面的两段代码,我们在L中创建了一个某个颜色的table,比如setcolor(colortable[1]),事实上是往L中放了一个表格,WHITE = {r = 1, g = 1, b = 1}。把整个struct都放入,只需使用下面这个循环:
int i = ;
while (colortable[i].name != NULL)
setcolor(&colortable[i++]);
自此,我们上面struct中所有的颜色都有了一张自己的table。
所以,field只是某个table中的,一个“name=value”对,name通常是一个字符串。这里的name也就是通常说的index,使用任意的lua认可的值都可以用来做它的name。这样一个“name=value”对被称为一个field。
3、registery
registery和其它的lua的表没什么却别。我们可以通过一个伪index(pesudo-index)在L中找到它;这个伪index是由宏LUA_REGISTRYINDEX定义的。我们也可以把这个伪index当做是普通的index来使用,但是不同的是,需要知道,它的value也不是在L里面。它的value不在stack中这一点非常重要,它决定了那些对stack本身做操作的函数是不适用的,比如lua_remove和lua_insert。
我们可以用下面的语句取到在registery中的,关键词为“key”的注册项:
lua_pushstring(L, "Key");
lua_gettable(L, LUA_REGISTRYINDEX);
因为他和其它的表没有区别,那么,和操作其它表一样操作它就好了。不过,因为所有的C库使用同一张registery,所以,命名上面我们要下些功夫,以免发生命名冲突。PIL里面推荐了一种保险的做法,我们可以选择一个我们代码里的静态变量的地址作为key:链接器不会给不同的静态变量分配相同地址,所以就不用担心重复问题了。如果要这么做,你需要调用函数lua_pushlightuserdata。在lua中,userdata就是一个普通的C value,而lightuserdata则是指C指针。我们在这里调用它把某个指针放到堆顶。具体可以看下面代码:
/* 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, -); /* convert to number */
当然,你也可以使用字符串作为registery的key,去多长都可以,你认为达到目的了就行。后面的懒得翻译了囧RZ
For such keys, there is no bulletproof method of choosing names, but there are some good practices, such as avoiding common names and prefixing your names with the library name or something like it. Prefixes like lua or lualib are not good choices. Another option is to use a universal unique identifier (uuid), as most systems now have programs to generate such identifiers (e.g., uuidgen in Linux). An uuid is a -bit number (written in hexadecimal to form a string) that is generated by a combination of the host IP address, a time stamp, and a random component, so that it is assuredly different from any other uuid.
lua中的table、stack和registery的更多相关文章
- Lua中使用table实现的其它5种数据结构
Lua中使用table实现的其它5种数据结构 lua中的table不是一种简单的数据结构,它可以作为其他数据结构的基础,如:数组,记录,链表,队列等都可以用它来表示. 1.数组 在lua中,table ...
- 递归打印lua中的table
在lua中,table是比较常用的数据形式,有时候为了打印出里面的内容,需要做一些特殊处理. 废话不多讲,直接粘代码: print = release_print -- 递归打印table local ...
- lua中遍历table的几种方式比较
当我在工作中使用lua进行开发时,发现在lua中有4种方式遍历一个table,当然,从本质上来说其实都一样,只是形式不同,这四种方式分别是: for key, value in pairs(tbtes ...
- Lua中的table函数库
table.concat(table, sep, start, end) concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组 ...
- lua中求table长度
关于lua table介绍,看以前的文章http://www.cnblogs.com/youxin/p/3672467.html. 官方文档是这么描述#的: 取长度操作符写作一元操作 #. 字符串的长 ...
- Lua中的table构造式(table constructor)
最简单的构造式就是一个空构造式{},用于创建一个空table. 构造式还可以用于初始化数组.例如,以下语句:days = {"Sunday", "Monday" ...
- lua中求table长度--(转自有心故我在)
关于lua table介绍,看以前的文章http://www.cnblogs.com/youxin/p/3672467.html. 官方文档是这么描述#的: 取长度操作符写作一元操作 #. 字符串的长 ...
- Lua中获取table长度
-- table.getn(tableName) 得到一个table的大小,等同于操作符# -- 要注意的是:该table的key必须是有序的,索引是从1开始的. --例如有序的 local xian ...
- lua中使用table实现类和继承
--因为只有当读写不存在的域时,才会触发__index和__newindex classA = {className = "classA",name="classAIns ...
随机推荐
- java中String、StringBuffer、StringBuilder的区别
java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可 ...
- HDU2389-Rain on your Parade-二分图匹配-ISAP
裸二分图匹配 /*--------------------------------------------------------------------------------------*/ #i ...
- redis性能测试tcp socket and unix domain
UNIX Domain Socket IPC socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket.虽然网络socke ...
- spring boot/cloud 应用监控
应用的监控功能,对于分布式系统非常重要.如果把分布式系统比作整个社会系统.那么各个服务对应社会中具体服务机构,比如银行.学校.超市等,那么监控就类似于警察局和医院,所以其重要性显而易见.这里说的,监控 ...
- php缓存技术(减少数据库服务器压力)
静态缓存(保存在磁盘上的静态文件,用PHP生成数据放入静态文件中) a) php操作缓存 i. 生成缓存 ii. 获取缓存 iii. 删除缓存 判断目录是否存在:is_dir() dirname ...
- 安装rpm包时遇到Header V3 DSA signature: NOKEY时解决办法
安装rpm包,特别是没有GPGkey校验,原因是rpm版本过低导致的. 代码如下: warning: rpmts_HdrFromFdno: Header V3 DSA signature: NOKEY ...
- c#模拟表单POST数据,并获取跳转之后的页面
直接看代码: using System; using System.Collections.Generic; using System.Linq; using System.Web; using Sy ...
- MyBatis学习--高级映射
简介 前面说过了简单的数据库查询和管理查询,在开发需求中有一些一对一.一对多和多对多的需求开发,如在开发购物车的时候,订单和用户是一对一,用户和订单是一对多,用户和商品是多对多.这些在Hibernat ...
- androd Sdk manager配置
Android Android SDK 配置步骤 启动 Android SDK Manager ,打开主界面,依次选择「Tools」.「Options...」,弹出『Android SDK Manag ...
- MySQL的启动脚本
MySQL的启动脚本#!/bin/bashmysql_port=3308mysql_username="admin"mysql_password="password&qu ...